Reputation: 2205
Let's see this example.
<html>
<body onload="alert((0.1234*300));alert((0.00005*300))"/>
</html>
Why the results are not as should be 37.02 and 0.015 but 37.019999999999996 and 0.015000000000000001 ?
Ps: 0.00005*300 make error while 0.0005*30 and 0.005*3 are ok.
Upvotes: 1
Views: 375
Reputation: 2669
When you display a Number
then its toString(radix)
function is used to convert it into a String
first. This function will round the number to a predefined amount of digits. So instead you might want to use toPrecision(precision)
, toFixed(digits)
or toExponential(fractionDigits)
. All of these functions convert Numbers
to Strings
but in contrast to toString
you can specify the amount of digits with their parameters.
And rounding is necessary when you're working with rational numbers here because the internal representation is binary and the external representation (as a String
) is decimal.
0.1234 is a rational number. It is quite easy to write it down in the decimal system because it is a decimal fraction (1234/10000). But in the binary system the representation is of infinite length. It starts with 0.000 and then continues endlessly with a repetend of 500 digits.
To make it possible to store this number it gets rounded from
1.1111100101110010010001110100010100111000111011110011010011010110101.. * 2^-4
to
1.1111100101110010010001110100010100111000111011110011 * 2^-4
which is the nearest IEEE754 double.
The difference is about 4.1966 * 10^-18 so the 0.1234 it's actually a 0.123399999999999995803..
If you try to display this number with JavaScript it will get converted to a string of characters. In the process it gets rounded to 0.123400000.. and truncated to 0.1234. So on the surface it still looks like 0.1234 even if it's slightly smaller.
When this number gets multiplied by 300 the result is 37.019999999999998741.. which has a finite representation in the binary system:
1.00101000001010001111010111000010100011110101110000100110001 * 2^5
But this number also has to be rounded to fit into a double:
1.0010100000101000111101011100001010001111010111000010 * 2^5
This is actually 37.019999999999996021.. but again you convert it to a string, so it gets rounded to 37.019999999999996.
If you just look at the digits of 0.1234 and 0.1234*300 you will notice that both numbers get rounded to 17 digits:
12339999999999999580..
37019999999999996021..
Upvotes: 1
Reputation: 73282
You need to have a good read of What Every Computer Scientist Should Know About Floating-Point Arithmetic
Upvotes: 8
Reputation: 344261
All numbers in JavaScript are represented in binary as IEEE-754 Doubles, which provides an accuracy to about 14 or 15 significant digits. Because they are floating point numbers, they do not always exactly represent real numbers (Source):
console.log(0.1234 * 300); // 37.019999999999996
console.log(0.00005 * 300); // 0.015000000000000001
You will also be interested in checking out the following post:
Upvotes: 5