0

I have always been coding in java and have recently started coding in javascript (node.js to be precise). One thing that's driving me crazy is add operation on decimal numbers;

Consider the following code

var a=0.1, b=0.2, c=0.3;
var op1 = (a+b)+c;
var op2 = (b+c)+a;

To my amazement I find out op1 != op2 ! console.logging op1 and op2 print out the following:

console.log(op1); 0.6000000000000001
console.log(op2); 0.6

This does not make sense. This looks like a bug to me because javascript simply cannot ignore rules of arithmetic. Could someone please explain why this happens?

Karan Ashar
  • 1,392
  • 1
  • 10
  • 23
  • Its the flaw of how numbers are stored in javascript , it stores numbers in the exponential form and hence some errors like this occur , its actually a problem with all the double precision floating point numbers which store information in the power of E . form – ShrekOverflow Apr 26 '12 at 17:31
  • 1
    See this : http://stackoverflow.com/questions/10313522/weird-java-fraction-behavior/10313578#10313578 – Denys Séguret Apr 26 '12 at 17:33
  • 2
    Welcome to floating-point numbers! – Etienne Perot Apr 26 '12 at 17:35
  • 3
    Possible duplicate of many many topics on SO :) – Florian Margaine Apr 26 '12 at 17:35
  • I'd really like to know how we must handle this few questions that happen many times a day. Is there a clear policy somewhere on this point ? – Denys Séguret Apr 26 '12 at 17:38
  • 2
    @dystroy this time its even someone with 92.1k reputation! –  Apr 26 '12 at 17:39
  • possible duplicate of [Is JavaScript's Math broken?](http://stackoverflow.com/questions/588004/is-javascripts-math-broken) – Bergi Apr 26 '12 at 17:58
  • @dystroy Yes, the policy is to vote (or flag) the question to be closed as a duplicate. For example, Bergi has evidently voted to close this as a duplicate of [Is JavaScript's Math broken?](http://stackoverflow.com/questions/588004/is-javascripts-math-broken), as doing so automatically generates the comment you see above. – Dan J Apr 26 '12 at 18:05

4 Answers4

3

This is a case of floating-point error.

The only fractional numbers that can be exactly represented by a floating-point number are those that can be written as an integer fraction with the denominator as a power of two.

For example, 0.5 can be represented exactly, because it can be written 1/2. 0.3 can't.

In this case, the rounding errors in your variables and expressions combined just right to produce an error in the first case, but not in the second case.

Neither way is represented exactly behind the scenes, but when you output the value, it rounds it to 16 digits of precision. In one case, it rounded to a slightly larger number, and in the other, it rounded to the expected value.

The lesson you should learn is that you should never depend on a floating-point number having an exact value, especially after doing some arithmetic.

Kendall Frey
  • 43,130
  • 20
  • 110
  • 148
0

That is not a javascript problem, but a standard problem in every programming language when using floats. Your sample numbers 0.1, 0.2 and 0.3 cannot be represented as finite decimal, but as repeating decimal, because they have the divisor 5 in it: 0.1 = 1/(2*5) and so on. If you use decimals only with divisor 2 (like a=0.5, b=0.25 and c=0.125), everything is fine.

afx
  • 1
0

This happens because not all floating point numbers can be accurately represented in binary.

Multiply all your numbers by some number (for example, 100 if you're dealing with 2 decimal points).

Then do your arithmetic on the larger result.

After your arithmetic is finished, divide by the same factor you multiplied by in the beginning.

http://jsfiddle.net/SjU9d/

a = 10 * a;
b = 10 * b;
c = 10 * c;

op1 = (a+b)+c;
op2 = (b+c)+a;

op1 = op1 / 10;
op2 = op2 / 10;
jbabey
  • 45,965
  • 12
  • 71
  • 94
  • So this is 10 years later but... I don't really understand why multiplying with a constant makes a difference here. Could you elaborate? – EnriqueDev Jan 06 '22 at 22:33
0

When working with floats you might want to set the precision on the numbers before you compare.

(0.1 + 0.2).toFixed(1) == 0.3

However, in a few cases toFixed doesn't behavior the same way across browsers. Here's a fix for toFixed.

http://bateru.com/news/2012/03/reimplementation-of-number-prototype-tofixed/

Larry Battle
  • 9,008
  • 4
  • 41
  • 55