0.1+0.2 === 0.3

JS Number = Double

0.1 + 0.2 / / 0.30000000000000004;
0.1+0.2= = =0.3 // false
Copy the code

It is clear from the code that 0.1+0.2 is not equal to 0.3 so what causes this result?

The Definitive JavaScript Guide Sixth edition - No3Chapter type specifies the number in JavaScriptNumberType is represented by IEEE754Standard definition of double precision64Unlike other programming languages (such as C and Java), JavaScript does not distinguish between integer and floating point values. All values in JavaScript are represented by a double precision floating point value (equivalent to a double in C and Java). Therefore, it is important to pay special attention to precision loss when performing numeric operations.Copy the code

The IEEE 754 standard

IEEE 754 uses the double-precision 64-bit format IEEE 754 Values to store 64-bit bits

Meaning:

  • S (sign) 1 bit is used to represent sign bits (positive and negative)
  • E (exponent) has 11 digits
  • M (Mantissa) 52 digits are used to indicate the mantissa

The storage mechanism for numbers in JavaScript

(s) * (m) * (2^e)

According to ECMAScript 5 specification, the range of e is [-1074, 971], so it can be concluded that the maximum value of js can be 1 * (2^ 54-1) * (2^971) = 1.7976931348623157e+308, This value happens to be the value of number.max_value; Similarly, it can be deduced that the minimum value that js can represent greater than 0 is 1 * 1 * (2 ^ -1074) = 5e-324, which is exactly the value of number.min_value.

So why do floating point numbers lose precision when being evaluated?

0.1 >> 0.0001 1001 1001 1001.. An infinite loop0.2 >> 0.0011 0011 0011 0011. An infinite loopCopy the code

Due to the limited storage space, so can only imitate the decimal round, but binary only 0 and 1 two, so into 0 round 1. This is part of the floating point in the computer operation error, loss of precision of the root cause.

Accuracy of large integers is lost

The precision loss of a large integer is essentially the same as that of a floating point number. The mantissa is up to 52 bits, so the largest integer that can be accurately represented in JS is math.pow (2, 53), which is 9007199254740992 in decimal.

Error greater than 9007199254740992 May be lost

9007199254740992 + 1
/ / lost 9007199254740992
9007199254740992 + 2
// Not lost 9007199254740994
9007199254740992 + 3
/ / lost 9007199254740996
9007199254740992 + 4
// Not lost 9007199254740996
Copy the code

Back to the question

So why doesn't 0.1+0.2 equal 0.3?

  • Because of the storage principle of the computer, resulting in the storage of floating point number in the computer, the storage is not accurate value, storage is an approximate value, display, display as a floating point value effect;
  • When floating point numbers are directly involved in the calculation or comparison, the actual value involved in the budget or comparison is also an approximation;
  • As a result, there will be errors in calculation or comparison, which will show the results of errors in special cases;

Ps: JavaScript states that even using scientific notation, data types are floating-point types, error of floating-point/exact loss of floating-point

Simulation calculation

First, 0.1 and 0.2 are converted to binary. For decimal to binary, the integer part is mod by two and arranged in reverse order. The decimal part is rounded by two and arranged in order

0.1 to binary 0.0 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011… (loop 0011)

0.2 Binary 0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011… (loop 0011)

Then according to IEEE 754 standard (s) * (m) * (2^ E) to represent

/ / 0.1
e = -4;
m = 1.1001100110011001100110011001100110011001100110011010 (52A)/ / 0.2
e = -3;
m = 1.1001100110011001100110011001100110011001100110011010 (52A)// Where m is the 52 decimal places, e is the exponent of m, and the whole number before the decimal point is the hidden digit s
// If the exponent e is found to be inconsistent, the right shift is generally used, because even if the right side overflow, the loss of precision is much smaller than the left side overflow
// Sum after transformation

e = -3; m = 0.1100110011001100110011001100110011001100110011001101 (52Bit) + e = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52A)/ / get
e = -3; m = 10.0110011001100110011001100110011001100110011001100111 (52A)// Keep one integer
e = -2; m = 1.00110011001100110011001100110011001100110011001100111 (53A)// We find that there are more than 52 bits, so we need to round them off, because we can't tell which one is closer, so the rule is to keep the even one, to get the final binary number
m=1.0011001100110011001100110011001100110011001100110100 (52A)// Then get the final binary number
1.0011001100110011001100110011001100110011001100110100 * 2^ -2 = 0.010011001100110011001100110011001100110011001100110100
// Now convert to decimal. A binary decimal is converted to decimal by the first decimal point *2 ^ -1, the second decimal point *2 ^ -2, and so on
// 可以利用等比数列求和公式,最终求得十进制数为0.30000000000000004
Copy the code

conclusion

So the final result of 0.1 + 0.2 is 0.30000000000000004

supplement

How to solve the problem of floating point loss of precision

Float (int, int, int, int); float (int, int); float (int, int, int);

    (0.1 * 10 + 0.2 * 10) / 10= = =0.3 // true
Copy the code