Why 0.1 + 0.2! = = 0.3? This is an interview question, which tests whether the basic skills of the candidates are solid. Today, we will analyze why the computer considers them not equal.
The storage of floating point numbers
The first step is to understand how floating-point numbers are stored in a computer. JavaScript uses eight bytes, or 64 bits, to represent a number. Each of these 64 bits is either a 0 or a 1.
Secondly, the biggest difference between a computer and a human brain is that a computer only knows base 2, while a human brain uses base 10, so 0.1 and 0.2 need to be converted into binary for analysis:
0.1.toString(2) / / 0.00011001100110011001100110011001100110011001100110011... An infinite loop
0.2.toString(2) / / 0.0011001100110011001100110011001100110011001100110011... An infinite loop
Copy the code
As the saying goes, “Life is limited, and knowledge is limitless. “Infinite” means that it is impossible to represent an infinite repeating decimal with a finite number of 64 bits, only approximate.
So how does a computer approximate 0.1 in base 2? According to IEEE 754, the 64 bits are divided into three parts: 64 = 1 + 11 + 52:
x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 1 ----11----- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 52 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Copy the code
- The first bit is the sign bit S(sign), which is used to represent positive and negative numbers, 0 for positive numbers and 1 for negative numbers
- Bits 2 through 12 are the exponent bits E(exponent), which store the exponent part
- Bits 13 through 64 are mantissa, which stores significant digits
Why is it divided into these three parts? Let’s start by thinking about how integers and decimals can be represented uniformly in the decimal case.
12345 = 1.2345-0.038 * 10 ^ 4 * 1 = 1 * 10 ^ (2) * 3.8Copy the code
Have you found that whether positive or negative numbers or decimals, can be expressed in this way, that is, scientific notation, as long as you know the symbol, exponent and significant number, then the number is determined. It is similar in binary, for example:
100110 = 1 * 2^5 * 1.0011-0.0001100110011 = -1 * 2^(-4) * 1.100110011Copy the code
A special feature of binary is that the significant digits are always 1, so you can store only the trailing digits of decimals, such as -0.0001100110011:
- The symbol bit 1 represents a negative number
- The exponent is minus 4
- The mantissa part is the decimal mantissa part, namely 100110011
The key is how do I store the minus 4 in the exponent position? We know that 11 bits can represent 2^11 = 2048 different numbers, that is, 0 ~ 2047. If negative numbers are considered, the range is -1023 ~ 1024.
- Set the first part of the 11-bit exponent to a sign bit, and use the last 10 bits to store the value
- Add 1023 before storing it, in which case it must be an unsigned integer
IEEE 754 uses the latter, so the index part stores binary 1111111011 1023-4 = 1019.
Safe number and maximum number
JS has a maximum safe integer:
Number.MAX_SAFE_INTEGER = 9007199254740991 / / 2 * * 53-1
/ / representation for: 1 52 * 1.1111111111111111111111111111111111111111111111111111 * 2 ^
// The mantissa bit is already 1
parseInt('11111111111111111111111111111111111111111111111111111'.2) / / 9007199254740991
Copy the code
Anything greater than this is considered unsafe, because an additional 1 is represented by at least 53 bits, i.e. :
1 * 2^53 * 1.00000000000000000000000000000000000000000000000000000 / / 2 * * 53
1 * 2^53 * 1.00000000000000000000000000000000000000000000000000001 / / 2 * * 53 + 1
Copy the code
Since the mantissa can only store 52 bits, the 53rd bit is lost, which means that 2**53 and 2**52+1 are represented in the same way, and they give the same result:
2**53 = 9007199254740992
2**53+1 = 9007199254740992
2**53= = =2**53+1 // true
Copy the code
So said.
- Numbers between 2^53 and 2^54 are only exactly even because the last bit is lost
- Numbers between 2^54 and 2^55 are only accurate multiples of 4, because the last two bits are lost
- Numbers between 2^55 and 2^56 are only accurate multiples of 8, because the last three bits are lost
- By analogy, losing N bits is an exact multiple of 2 to the N
Since the maximum exponent bit is 1024, the maximum number that can be represented is:
1 * 2 ^ 1024 * 1.00000000000000000000000000000000000000000000000000000000000...Copy the code
At this point, the number of bits in the exponent part is full, and the number of bits in the digit part is full. Any number exceeding this value will be equal to this number, so JS defines this number as Infinity:
2**1024 // Infinity
Copy the code
The largest number that JS can represent is:
1 * 2^1023 * 1.1111111111111111111111111111111111111111111111111111
Number.MAX_VALUE / / 1.7976931348623157 e+308
Copy the code
Calculate 0.1 + 0.2
Let’s look at the storage mode of 0.1 and 0.2:
0.1.toString(2)
/ / the actual value: 0.00011001100110011001100110011001100110011001100110011001100... An infinite loop
/ / scientific notation: 1 * 2 ^ (4) * 1.1001100110011001100110011001100110011001100110011001 52 is reserved
/ / that is stored value: 0.0001100110011001100110011001100110011001100110011001101
0.2.toString(2)
/ / the actual value: 0.0011001100110011001100110011001100110011001100110011... An infinite loop
/ / scientific notation: 1 * 2 ^ (3) * 1.1001100110011001100110011001100110011001100110011001 52 is reserved
/ / that is stored value: 0.001100110011001100110011001100110011001100110011001101
Copy the code
Calculate their sum:
0.0001100110011001100110011001100110011001100110011001101 0.001100110011001100110011001100110011001100110011001101 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 0.0100110011001100110011001100110011001100110011001100111 Scientific notation is expressed as: 1 * 2 ^ (2) * 1.0011001100110011001100110011001100110011001100110011Copy the code
This result in decimal is exactly 0.30000000000000004