SKing7
SKing7

Reputation: 2356

How is a Javascript number stored in memory

First, we see the code below:

result = 0.1 + 0.2;     
alert(result===0.3);// false
result=100.1+100.2;
alert(result===200.3);//true

I believe that 0.1 and 100.1 (100+0.1) are stored similarly in memory, since the decimal is .1 in both of them.

So, why is the result of the addition different?

Upvotes: 1

Views: 2475

Answers (3)

Paul
Paul

Reputation: 141839

They are not stored the same in memory: http://steve.hollasch.net/cgindex/coding/ieeefloat.html

0.1 in binary:

0.1 * 2 = 0 + 0.2
0.2 * 2 = 0 + 0.4
0.4 * 2 = 0 + 0.8
0.8 * 2 = 1 + 0.6
0.6 * 2 = 1 + 0.2
0.2 * 2 = 0 + 0.4
0.4 * 2 = 0 + 0.8
0.8 * 2 = 1 + 0.6
0.6 * 2 = 1 + 0.2

As you can see, after the 0.2 repeated the whole pattern (0011) will just keep repeating, so 0.1 is 0.0001100110011001100110011... repeating forever

To represent that in a 23 bit mantissa we have to shift it left until we have a 1 before the decimal point (after shifting the bits left 4 places and removing the 1 before the decimal we have 100110011...) and then round at the 23rd bit, and we get: 10011001100110011001101.

Since we shifted 4 places our exponent is 127-4 (127 is the 32 bit bias). 123 in 8 bits of binary is 01111011, all that's left is the sign bit, which we know is 0 since 0.1 is a positive number. So each component of the 32 bit binary number is:

sign: 0
exponent: 01111011
mantissa: 10011001100110011001101

0.1 is represented as 00111101110011001100110011001101 in a floating point number.

Converting back we have to break it back apart and then convert the exponent back to a decimal integer (123). We shift the mantissa (with an assumed 1 in front) to the right (127 - 123 = 4) times and get : 0.00011001100110011001101101 then we convert this back to decimal:

0*1/2 + 0*1/4 + 0*1/8 + 1/16 + 1/32 + 0*1/64 + 0*1/128 + 1/256 + 1/512 + 
0 + 1/4096 + 1/8192 + 0 + 1/65536 + 1/131072 + 0 + 1/1048576 + 1/2097152 + 
0 + 1/16777216 + 1/33554432 + 0 + 1/134217728

Which if you do the math gives you something closer to 0.100000001, than to 0.1. That's because we rounded at the 23rd bit. 0.1 cannot be stored in binary since it repeats forever, so after the 23rd bit we have inaccuracies. When you do arithmetic on a number those inaccuracies are carried through, and the errors can grow to be much larger.

If you do the same thing with 100.1 you get:

1100100.0001100110011001100... repeating forever:

Shift right 6 times and removing the 1 before the decimal round to 23rd bit: 10010000011001100110011

Exponent is 127+6 = 133 (1000 0101)

Sign is 0 again, so you have:

01000010110010000011001100110011

Upvotes: 6

Bakudan
Bakudan

Reputation: 19482

This is the IEEE 754 wikipedia implementation result. There is not way to present every float point number, and it is present in every language following the IEEE 754 standart. This code snippet will have the same result in any language:

var sum = 0.0;
for (var i = 0; i < 10; i++ )
{
    sum += 0.1;
}
// sum = 0.9999999999999999

0.1 is exactly one of the numbers that do not have an exact representation wikipedia.

C# has a special type Decimal MSDN which is appropriate for financial and monetary calculations, which internaly is a structure.

Upvotes: 0

Ramesh
Ramesh

Reputation: 13266

In addition to Paul P.R.O's answer

This is not a problem with javascript alone. In C# double exhibits the same behavior

double a = 0.1, b = 0.2;
Console.WriteLine((a + b)==0.3); //Prints False

Hence,it is advisable to use decimal in c# for precision. For javascript you should use .toFixed to work with currency operations. For more inside into numbers in javascript check out http://www.hunlock.com/blogs/The_Complete_Javascript_Number_Reference#quickIDX0

Upvotes: 0

Related Questions