Picture of jgehtland

Your Weird Ruby Item of the Day

  • Posted By Justin Gehtland on August 01, 2008

UPDATE: See the follow-up here.

Ok. I don’t really pretend to know why this is happening, but Chad and I have verified this on several operating systems. And, yes, the number we found was totally by accident.

To get weirded out, just perform the following in irb:

s = "40.87" 
f = s.to_f
ft = f * 100
fti = ft.to_i

If you are like us (Ruby version 1.8.6, patchlevel tested at 0 and 114), your end result there is 4086.

When we started digging a little deeper, the float value stored in the “ft” variable is actually less than 4087, but greater than 4086.9999999999995. We cast around looking for other numbers where this happens, but have been unable to find any.

If anybody has a good explanation, we’d love to hear it.

Oh, and to fix it? Just use:

ft.round.to_i

Of course!

Comments
  1. Greg VaughnAugust 01, 2008 @ 08:18 PM

    to_i truncates any decimal portion http://www.ruby-doc.org/core/classes/Float.html#M000550

  2. Hongli LaiAugust 01, 2008 @ 09:54 PM

    Yes. This is due to the nature of floating point numbers. Floating point numbers on most platforms are represented by the format as defined in IEEE 754-1985. Floating point numbers, as humans use them, are base 10. But floating point numbers in computers are base 2, and not all base 10 floating point numbers can be accurately represented by base 2. For example, 0.6 cannot be represented in base 2 with a finite number of bits. If you try to do the conversion then you will end up with an infinite number of bits after the decimal point.

    Computer programmers must always keep this fact in mind. Floating point calculations are never entirely accurate, and depending on how they’re done, some information will be lost. That’s why the financial world don’t use floating point numbers to represent money. Instead, they use integers.

  3. Hongli LaiAugust 01, 2008 @ 09:56 PM

    A follow-up to my last comment. Wikipedia explains the problem clearly: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

  4. Craig BuchekAugust 01, 2008 @ 10:59 PM

    I think this would fall under the guise of “What Every Computer Scientist Should Know About Floating-Point Arithmetic”: http://docs.sun.com/source/806-3568/ncg_goldberg.html

    Basically, rounding errors in the conversions between base-2 and base-10.

    Python gives the same results: >>> int(40.87 * 100) 4086

  5. BrandonAugust 02, 2008 @ 12:25 AM

    I’m not a math wizard, but I think this would be expected in any language. Float operations simple aren’t predictable, so every operation causes you to lose some accuracy/precision.

    Here’s a fun one:

    4.1%2 => 0.0999999999999996

  6. Rob SanheimAugust 02, 2008 @ 02:03 AM

    This is a commonly known issue with floating point operations in just about any language. See http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems for more details. Here’s a clearer illustration of the same issue:

    irb(main):007:0> puts 'not equal' unless (3.2 - 2.0) == 1.2

    So, uh, use big decimal when you need real precision. =)

  7. jgehtlandAugust 02, 2008 @ 01:57 PM

    Ok, I’ve clarified in the followup post. Sheesh, nothing better than looking dumb in public! ;-)