Why you can’t trust Javascript’s Addition, NodeJS Included
By trent on 23 Feb in Javascript
You’ve been around javascript long enough to know there are some really strange quirks. Here is one I’ve not seen before. Consider very basic addition. If you want to try this just open your javascript console in Chrome or Firefox and simply enter:
4.3 + 8.0 + 6.15
Think the answer is 18.45? Wrong, you’ll get 18.450000000000003.
Ok, now lets rearrange those numbers and try it again:
4.3 + 6.15 + 8.0
Now you will get 18.45. After rearranging these some more and here are the results:
8.0 + 4.3 + 6.15 // 18.450000000000003 8 + 6.15 + 4.3 // 18.45 8.0 + 6.15 + 4.3 // 18.45 4.3 + 1 + 6.15 // 11.45 4.3 + 4 + 6.15 // 14.450000000000001 100  (4.3 + 4 + 6.15) // 85.55 100  14.450000000000001 // 85.55
It seems to differ depending on the position within the addition sequence and also the numbers being added. So far these all round down, but what happens when you encounter this?
4.3 + 6.15 + 3.7 + 1.85 // 15.999999999999998 4.3 + 6.15 + 1.85 // 12.299999999999999
Ahh, now you run into some borderline issues. What if you are validating that you have $16?
16 == 4.3+6.15+3.7+1.85 // false 16 === 4.3+6.15+3.7+1.85 // false
So when do you know if you actually have 15.999999999999998 and when it is just a silly inconsistancy?
After some googling there are a few possible work arounds, like (8.0 + 4.3 + 6.15).toFixed(2) but you don’t always know how many decimal places you should need.
So you think this is just a silly client side validation issue? THINK AGAIN. This includes NodeJS as well, possibly others. This could be going into your database. Possibly over/under charging payments. Maybe you’re processing some type of precise calculations. If you know the number of decimal places you need you better ensure you’re rounding to that many decimal places.
Sure there is some fancy explanation (See http://floatingpointgui.de/), but is it broke? As far as I’m concerned, YES. Please, someone, prove me wrong!
11 Responses

t2n  Feb 25, 2013

Enrico  Feb 25, 2013
This isn’t a javascript bug :)
If you do the same additions in C# you get the same results
I think it’s all about the x86 architecture 
Álvaro G. Vicario  Feb 25, 2013
That’s how computers work. Handling floating point numbers has two basic restrictions:
1. Computers use base 2, not base 10
2. Computers use a fixed size to store numbersIn your first example,
4.3 + 8.0 + 6.15
, 4.3 has two digits in base 10 but it’s periodic in base 2 and something similar happens with 6.15. Only 8.0 has a exact representation in base 2 (please note it’s an integer).Broken? Well, 1/3 has a exact representation in base 3 but not in base 10. That doesn’t make base 10 broken.
You might enjoy this guide: What Every Programmer Should Know About FloatingPoint Arithmetic

Right, I understand there is reasoning behind why it functions this way. Lets take a scenario. 90% of programmers developing a simple shopping cart would add their total with simply:
var total = 4.3 + 6.15 + 1.85;
I guarantee very few of them will take into account these issues, and apply a work around, like rounding or converting the decimal dollar into cents so they are integers. Point of the article is you can’t simply trust it, you need to apply an approach to reassure the correct result.

Robert  Feb 26, 2013
A programmer dealing with numbers that are inherently decimal, like currency, should know better than to use floating point math on those numbers. There’s really no excuse for not knowing how floating point math is implemented on computers (and “90% of programmers” don’t make a right).

Martijn  Feb 26, 2013
Are you also one of those people who use FLOAT type columns in MySQL to store currency values? I can’t remember how many times I had to tell PHP “developers” not to do that.
Please excuse the sarcasm, but as Robert and others have pointed out, if you consider yourself a programmer, you should know how floats behave.

bungle  Feb 26, 2013
Time to read about IEEE 754.

It’s not broken, trust me, I’m an engineer.
Have you ever noticed that in math classes you talk about real numbers but while programming you don’t have them but variables with type float? The programmers before you did a hell of a job making sure the arithmetic in your programs works really close to what you know from mathematics, and the fact that people can have a career in IT and think they are using real numbers just proves how well their idea works.You should also be careful about big integers, since JS will convert big ones to floats, eg.:
9007199254740991+1 is 9007199254740992
but
9007199254740991+2 is still 9007199254740992Reading:
http://en.wikipedia.org/wiki/Real_number
http://en.wikipedia.org/wiki/Floatingpoint_numberA lot of nice theory:
http://nm.mathforcollege.com/topics/floatingpoint_representation.html 
@Robert, @Martijn
My point wasn’t that 90% makes it right, not at all. I even stated in the article there is a reason for it (though I don’t claim to be an expert), but the quick point was that developers need to use more assuring approaches, don’t just trust it. 
Holy Microshit!!!!!!!
So, I was born again.
#includeint main (int argc, char *argv[]) {
printf("%0.32f\n", 4.3 + 8.0 + 6.15);
return 0;
}

Herp Derp  Sep 29, 2013
The solution is pretty simple: use a decimalnumber library if your language (in this case, javascript) doesn’t have a builtin decimal type. I’m using the “num” library for JS: https://github.com/shtylman/nodenum
in python
>>> 4.3 + 8.0 + 6.15
18.450000000000003
>>> 4.3 + 6.15 + 8.0
18.45
>>>
solution:
https://github.com/dtrebbien/BigDecimal.js