Taken from Floating point accuracy problems.
Floating-point numbers cannot precisely represent all real numbers, and that floating-point operations cannot precisely represent true arithmetic operations, leads to many surprising situations. This is related to the finite precision with which computers generally represent numbers.
For example, the non-representability of 0.1 and 0.01 (in binary) means that the result of attempting to square 0.1 is neither 0.01 nor the representable number closest to it. In 24-bit (single precision) representation, 0.1 (decimal) was given previously as:
e = −4
s = 110011001100110011001101, which is 0.100000001490116119384765625 exactly.
Squaring this number gives 0.010000000298023226097399174250313080847263336181640625 exactly.
Squaring it with single-precision floating-point hardware (with rounding) gives 0.010000000707805156707763671875 exactly. But the representable number closest to 0.01 is 0.009999999776482582092285156250 exactly.
I needed a table to store some text and its index in a list at which the text occured. So as part of my migration, I decided to make sure the schema did not add to my legacy database structure, but relationally associate it. So part of the schema involved specifying the ‘index’ column, which I defined as
CREATE TABLE `meow` (
`index` tinyint(3) unsigned NOT NULL DEFAULT 1,
Now I thought I was safe as I had not used something like int(11), something unfortunately I have come across previously *shudder*. Off I go, happily plodding along with my model and code, till I actually needed to implement the association.
I wrote a simple spec test for it:
Cat.meows = Meow.new(:index => 2)
cat_meows = Cat.meows
And then inside my model Cat, I had:
has_many :meows, :foreign_key => 'cat_id', :class_name => 'Meow'
Seems simple, doesn’t it! AHA! You fool! You thought you could do this and life would be easy and wonderful and the world would make sense!
Such naivete! Adorable!
When I ran the spec and started getting errors which interpreted the `index` as boolean, I was intrigued. Looking at the API, I find this:
By default, the MysqlAdapter will consider all columns of type tinyint(1) as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your application.rb file:
ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false
Now while the fix seems simple enough, I would like to point out that this is a very neat and elegant solution for a problem that simply should not have existed! Had Rails made the assumption about a `bit(1)` field, then I would have been fine. Had they made the assumption about `tinyint(1)`, even then I would not have complained. Even the MySQL docs list `tinyint(1)` only as a boolean. Anything else, is simply not a boolean. Rails however, treats all declarations of `tinyint` as booleans. Which is annoying! Not hard to fix, not complicated, but annoying.
Why couldn’t they make that assumption about the `bit` field ?