Writing in the front
There are some special calculations in JavaScript, such as 0.1 + 0.2 = 0.30000000000000004(this problem exists not only in JavaScript, but also in C++ and Java, These strongly typed languages encapsulate methods to solve this problem. Presumably everyone knows that this is due to the data length interception problem when storing, but how the computer is to store and calculate these values, this article combined with a number of computer basic knowledge to explain this point.
More articles on my Github and personal public number [Whole cliff Road], welcome to watch [front knowledge points], if there is benefit, don’t pay, little hands point a Star
Read this article
- Conversion between decimal and binary
- How computers store and compute JavaScript values
To understand the computing principle of computer 0.1 + 0.2, you need to know the following knowledge in advance
Decimal and binary conversion
Conversion of positive integers
- Divide by two mod, reverse order, high zero complement
- Why do you need to fill bits: The CPU determines how many bits of data can be stored in a register according to the width of the data bus
Computer word length refers to the number of binary bits in which operations are performed. It can be divided into 8, 16, 32, or 64 bits, depending on the width of the data bus. For example, a Pentium is 32-bit, which means that the processor’s registers can hold 32 bits of data.
The conversion of negative integers
- Convert the absolute value of a negative integer into binary, and add 1 to the negative integers
Conversion of floating point numbers
- The integer place is converted normally, and the decimal part is rounded by 2, and arranged in order
The storage of floating point numbers in a computer
- Floating-point numbers are converted to binary and represented by scientific notation.
- Floating-point storage is implemented in accordance with
IEEE754 standard
Can be divided into two types:
- Single precision Float–32 bits (4 bytes)
- Double–64 bits (8 bytes)
IEEE standard
Before the 1980s, every computer manufacturer defined its own rules for representing floating-point numbers and the details of the operations they performed. And it’s less about precision and more about speed and simplicity.
In 1985, IEEE 754 standard floating point number representation and operation rules were introduced, so that the representation and operation of floating point numbers are portable.
Binary floating point arithmetic standard in IEEE storage format:
V is equal to minus 1 to the S times M times 2 to the ECopy the code
-
(-1)^s is the sign bit. When s=0, V is positive; When s is equal to 1, V is negative.
-
M is the significant digit, mantissa bit, greater than or equal to 1, less than 2.
-
2^E is the exponent bit.
-
For example
- Under the decimal
5.0 = 5 * 10 to the 0
- Under the binary
5.0 = 101.0 = 1.01 * 2 ^ (2) -- - > (1) ^ 0 * 1.01 * 2 ^ (2) -- - > S = 0, M = 1.01, E = 2Copy the code
Storage format
-
For a single precision floating point number, that is, a 32-bit floating point number, the highest 1 bit is the sign bit S, the next 8 bits are the exponent E, and the remaining 23 bits are the significant number M.
-
For a double-precision floating point number, that is, a 64-bit floating point number, the highest 1 bit is the sign bit S, the next 11 bits are the exponent E, and the remaining 52 bits are the significant number M.
A few points to pay attention to when storing
-
Mantissa bit M(significant digit bit)
- According to the IEEE 754 standard, when storing M internally in a computer, the first digit of this number is always 1 by default, so it can be omitted to save only the latter part. For example, when saving 1.01, save only 01, wait until the time to read, and then add the first 1. The purpose of this is to save 1 significant digit. For example, for a 32-bit floating point number, M is left with only 23 bits. After the first 1 is omitted, it can store 24 significant digits.
-
The index of an E
- First, E is an unsigned integer. That means that if E is 8 bits, it has a range of values
2 ^ 0 ~ 8-1 = 0 ~ 255
; If E is 11 bits, its value range is0 ~ 2 ^ 11-1 = 0 ~ 2047
. - But we know that E can be negative in scientific notation, so
IEEE 754
Specifies that the true value of E must be subtracted by an intermediate number, which is 127(-127~128) for an 8-bit E; For the 11-bit E, the middle number is 1023. - For example, E of 2^10 is 10, and when stored as a 32-bit floating point number, it must be stored as 10 + 127 = 137, i.e
10001001
. If you want to save it as a 64-bit floating point number, it will be saved as 10 + 1023 = 1033, i.e10000001001
.
- First, E is an unsigned integer. That means that if E is 8 bits, it has a range of values
-
The exponent E can be divided into three cases:
- E is not all 0 or all 1. In this case, floating-point numbers are represented by the rule above: the calculated value of the exponent E is subtracted from 127 (or 1023) to get the real value, and the significant number M is preceded by the first 1.
- E is all 0. In this case, the exponent E of the floating point number is equal to 1-127 (or 1-1023), and the significant number M is no longer added to the first 1, but is reduced to a 0. XXXXXX decimal. And I do that to represent plus or minus zero, and very small numbers that are close to zero.
- E is all 1. In this case, if the significant digits M are all zeros, it means ± infinity (depending on the sign bit s); If the significant digit M is not all zeros, it is not a number (NaN).
-
There is only one numeral-related type in JavaScript — Number — and it is stored as a double floating-point Number, represented as a 64-bit fixed-length equivalent to the standard double
The storage details
Take 0.1 + 0.2 as an example
-
Convert to binary:
// 0.1 0.00011 0011 0011... (0011 loop) // 0.2 0.0011 0011 0011... Circulate (0011)Copy the code
-
Converting to IEEE754 storage:
// 0.1 (-1)^0 * 1.1 0011... * 2^(-4) => S = 0, M= 1.1 0011... (0011 loop), E = -4 => Actual storage index bit: -4 + 1023 = 1019 => 11 1111 1011 //0.2 (-1)^0 * 1.1 0011... * 2^(-3) => S = 0, M= 1.1 0011... (0011 loop), E = -3 => Actual storage index bit: -3 + 1023 = 1020 => 11 1111 1100Copy the code
-
Actual storage:
/ / 0.1 storage 0 011 1111 1011 1001100110011001100110011001100110011001100110011010 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (11) S M E (52) / 0.2 / storage 0, 011, 1111, 1100 1001100110011001100110011001100110011001100110011010 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (11) S M E (52)Copy the code
Computation of floating point numbers in a computer
Operation steps
The calculation is divided into six steps
-
Check operands
- Check for the 0, Infinity, and NaN operands
-
To order
- The operation of aligning the codes of two calculated floating point numbers.
- The specific operation is: to find the difference between the two floating point order code, in accordance with the small order alignment of the large order, the two floating point order code alignment, while the small order code corresponding to the floating point number mantail corresponding to the right shift, to ensure that the value of the floating point number unchanged.
- * Note: The rule of order versus order is small versus large. Because if the large order is opposite to the small order, the high part of the mantissa’s numerical part needs to be moved out, while the small order is opposite to the large order, the low part of the mantissa’s numerical part needs to be moved out, so the loss of accuracy is smaller.
- * Note: Since the manstail moves to the right with the lowest displacement out, certain accuracy will be lost. In order to reduce the error, a number of removed bits can be reserved for rounding later.
-
Mantissa calculation
- The operation of adding and subtracting the mantissa after the order is mainly carried out, and the double sign method is used to judge whether the overflow occurs.
-
The results are normalized
- The first: normalization to the right: If overflow occurs in the previous step, the mantail is shifted 1 bit to the right, and the order code is +1.
- The second: left normalization: If there is no overflow in the previous step and the highest bit of the number range is the same as the sign bit, the mantail moves 1 bit to the left and the order code -1 until the highest bit of the number range is 1.
-
Rounding processing
- Because floating point numbers do not represent all numeric values exactly, they must be rounded before being stored.
- There are five ways to do it,
IEEE 754
Default rounding mode: Round to nearest, ties to even: if two numbers are equally close, take the even value (Round(0.5) = 0; Round (1.5) = 2; Round (2.4) = 2; Round (2.5) = 2; Round (3.5) = 4)
-
Overflow judgment
Operation details
-
Binary representation of the original 0.1 and 0.2
0.1 = 1.1001100110011001100110011001100110011001100110011010 * 0.2 = ^ 2-4 1.1001100110011001100110011001100110011001100110011010 * ^ 2-3Copy the code
-
As you can see, the order of 0.1 is -4 and the order of 0.2 is -3. According to the principle of small order versus large order, we need to change the order of 0.1 to -3, so the mantail part needs to be shifted one bit to the right. For the storage after the order 0.1, it is:
0.1 = 0.11001100110011001100110011001100110011001100110011010 * 0.2 = ^ 2-3 1.1001100110011001100110011001100110011001100110011010 * ^ 2-3Copy the code
-
The mantissa after order 0.1 spilled one bit, which was exactly 0, and we discarded it, so the storage before the final calculation was
/ / 0.1 0, 01111111100, 1100110011001100110011001100110011001100110011001101 / / 0.2 0. 01111111100 1001100110011001100110011001100110011001100110011010Copy the code
-
The two binaries are added
0 01111111100 1100110011001100110011001100110011001100110011001101 + 0 01111111100 1001100110011001100110011001100110011001100110011010 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- = 0, 01111111100, 10110011001100110011001100110011001100110011001100111Copy the code
-
In the result, the mantissa part has been carried and exceeds 52 bits, so the order part is increased by 1 (multiplied by 2), that is, the order part changes from the original -3 to -2, so the order part is 01111111101. The mantissa is moved one bit to the right (divided by 2) and rounded (the last bit is 1 and therefore the lowest carry) to get the final store:
// This step is to create 0.1 + 0.2! = = 0.3 0, 01111111101, 1011001100110011001100110011001100110011001100110011Copy the code
-
Converts the final result to a decimal number of
2 to the minus 2 plus 1 plus 1 to the minus 1 plus 0 times 2 to the minus 2 plus 1 times 2 to the minus 3 plus 1 times 2 to the minus 4 plus... = 0.3000000000000000444089209850062616169452667236328125Copy the code
-
Finally, due to the accuracy problem, only 0.30000000000000004 is taken (this step is when we see the final calculation result).
The solution
- The floating-point number is converted to an integer and then calculated
- use
toFixed()
Round off - Custom handlers
- Reference library
- Math.js
- decimal.js
Write in the last
If you find this article helpful, please like it and share it with more people who need it!
Welcome to pay attention to [Quanzhendaolu] and wechat public account [Quanzhendaolu], to get more good articles and free books!
There is a need [Baidu] & [bytedance] & [JD] & [ape counselling] within the push, please leave a message oh, you will enjoy the VIP level extreme speed within the push service ~
Past oliver
The interviewer asks you<img>
What elements do you say
Long [word] baidu and good interview after containing the answer | the nuggets technology essay in the future
Front end practical regular expression & tips, all throw you 🏆 nuggets all technical essay | double festival special articles
HTML Tabindex
A few lines of code to teach you to solve wechat poster and TWO-DIMENSIONAL code generation
Vue3.0 Responsive data principle: ES6 Proxy
Read on to make your interviewer fall in love with you
Remember a painful experience
Front-end performance optimization -HTML, CSS, JS parts
Front-end performance optimization – Page loading speed optimization
Front-end performance optimization – Network transport layer optimization