How Good Is This?

>> a = 79.99 * 100
=> 7999.0
>> a.floor
=> 7998
>> b = 7999.0
=> 7999.0
>> b.floor
=> 7999

I’ll tell you. It’s not good. I hate floating point calculations. Happy new year!

18 Comments (Closed)

Wow! That’s a problem. Also, a == b returns false. This seems like a Ruby bug to me.

WyattWyatt at 02.01.08 / 13PM

When I try this in the Firebug console, I actually get a value of 7998.999999 for the first calculation, which explains the weird a.floor result… Doesn’t make things any better though.

RonRon at 02.01.08 / 13PM

No, this is not a bug. It’s just the nature of floating point math. If you need to compare floats, then you need to use a delta (Google for “ruby floating point compare” or something like that).

JeremyJeremy at 02.01.08 / 13PM

No, you’re right. It’s not a bug. It’s what most languages do with floating points. It’s more of a gotcha.

The thing that I thought was odd was that Ruby shows the result of the first calculation as you’d like rather than doing what JavaScript does (7998.999999) but the underlying number is actually more like 7998.99999 than the 7999.0 that Ruby tells you it is. I just found that misleading.

DanDan at 02.01.08 / 14PM

I can’t try this out right here, but can you tell me what happens when you do this? >> c = 79.99 * 100.0 => ? >> c.floor => ?

JaapJaap at 02.01.08 / 14PM

Yup… good gotchas indeed! In the same vein: require 'math' =>true (log(1000)/log(10)+1).to_i =>3 1000.to_s.size =>4 :(

BlackPignoufBlackPignouf at 02.01.08 / 15PM

Jaap: you get 7998 again but if you do 799.9 * 10.0 and floor that you get 7999. This kind of thing is what always happens though. Its just Ruby’s inspect looking correct that confused me.

DanDan at 02.01.08 / 16PM

If you need closer to exact floating point calculations without the rounding error, try the ruby BigDecimal library. It appears to use an internal string representation of floating point numbers, and uses them for calculation, so there is no ‘machine delta’ problem. It is a bit slower than straight floating point math, but if the result being accurate is more important…

korishevkorishev at 02.01.08 / 17PM

Hola, soy Herzeleyd y estoy buscando diseñadores para crear un logo de mi web, todo lo que pido y ofrezco lo podreis encontrar aquí

Espero que no os incomode el mensaje.

Cualquier diseñador, amigo, blogger o lo que sea que conozcais, que pudiera estar dispuesto a presentar un logo, sería de gran ayuda. Cuanta más gente lo sepa y pueda ayudar, mucho mejor.

Muchas gracias a tod@s.

HerzeleydHerzeleyd at 03.01.08 / 20PM

Hi Dan, I get the same thing in python:

import math a = 79.99 * 100 math.floor(a) 7998.0 b = 7999.0 math.floor(b) 7999.0

Gary Stidston-BroadbentGary Stidston-Broadbent at 05.01.08 / 14PM

Go with BigDecimal.

ynwynw at 07.01.08 / 23PM

Hi there, same happens in matlab, which is meant for technical computing. a = 79.99*100 b = 7999 floor(a) = 7998 floor(b) = 7999 When I subtract both number (b-a) I get a difference of 9.094947017729282e-013 which is 2^12 times the machine precision. I know its a gotcha in floating point arithmetic but it would be cool if someone could give a thorough explanation of what exactly “goes wrong” here.

JeroenJeroen at 09.01.08 / 10AM

Jeroen, Wikipedia is your friend And they can explain floating point accuracy problems much better than I.

korishevkorishev at 13.01.08 / 06AM

And, confirming what Wikipedia states, Perl (actually the POSIX math library so this affects C as well) has the same rounding trouble. Cranking up the precision here to expose it:

$ perl -e ‘use POSIX qw(floor); $a=79.99*100; printf “a=.22f\nfloor(a)=.22f\n”, $a, floor($a);$b=7999.0; printf “b=.22f\nfloor(b)=.22f\n”, $b, floor($b);’

Outputs: a=7998.9999999999990905052982 floor(a)=7998.0000000000000000000000 b=7999.0000000000000000000000 floor(b)=7999.0000000000000000000000

SteveSteve at 17.01.08 / 21PM

Great :). Happy new year too you. Greetings

NoclegiNoclegi at 19.01.08 / 16PM

Thanks korishev, interesting stuff …

JeroenJeroen at 21.01.08 / 12PM

For what it’s worth, some microprocessors have had BCD (binary coded decimal) modes. The 6502 was one.

timothytoetimothytoe at 01.02.08 / 21PM

Floating points are approximations, always have been. You need to do some magic to compare them, but it’s possible. There is a short book floating around somewhere called “what every computer science major should know about floating points” or something like that. It’s helpful if you can find it.

Xac StegnerXac Stegner at 24.03.08 / 23PM

About This Article