Brief
One day a friend asked me, "JS calculation 0.7 * 180 how can be equal to 125.99999999998, the pit is too many!" "At the time I guessed that the binary represents the numeric value when the Round-off error occurred, but it was not clear how it was caused, and what method to circumvent. So spent 3 weeks to understand this problem, in the process of learning also found not only 0.7 * 180==125.99999999998, but also the following pits
1. The famous 0.1 + 0.2 = = = 0.30000000000000004
2. 1000000000000000128 = 1000000000000000129 = =
IEEE 754 floating-point
It is well known that JS has only number of this numeric type, while numbers are encoded with IEEE 754 64-bit double-precision floating-point numbers. Floating-point representation has the following characteristics:
1. The range of values that a floating-point number can represent is much larger than the value range of the integer representation of the equivalent.
2. Floating-point numbers cannot accurately represent all values within their value range, while signed and unsigned integers are the exact representation of each value within the range of their values;
3. Floating-point numbers can only accurately represent m*2e values;
4. When the biased-exponent is 2e-1-1, the floating-point number can accurately represent the integer values within the range;
5. When biased-exponent is not 2e-1-1, the floating-point number cannot accurately represent the integer values within the range.
Since some values cannot be accurately represented (stored), the deviation becomes apparent after the calculation.
For more information on floating point numbers, refer to the following articles:
Basic field: Detail the original code, anti-code and complement (http://www.cnblogs.com/fsjohnhuang/p/5060242.html)
Base wild: Elaborate unsigned integers (http://www.cnblogs.com/fsjohnhuang/p/5078290.html)
Base wild: Elaborate signed integers (http://www.cnblogs.com/fsjohnhuang/p/5082829.html)
Base wild: Detail floating point (http://www.cnblogs.com/fsjohnhuang/p/5109766.html)
Why 0.1 + 0.2 = = 0.30000000000000004?
In the example of generating error value in floating-point operation, the most famous should be 0.1 + 0.2 = = = 0.30000000000000004, how famous is it? Look at this website and know http://0.30000000000000004.com/. That is to say, not only does JavaScript produce this problem, but when you use the IEEE 754 floating-point floating-point encoding to represent floating-point numbers, this kind of problem arises. Let's analyze the whole operation process.
1. The binary representation of 0.1 is 1.1001100110011001100110011001100110011001100110011001 1 (0011) + * 2^-4;
2. When the 64bit storage space cannot store the complete infinite loop decimals, and the IEEE 754 floating-point takes round to nearest, the tie to even rounding mode, Therefore 0.1 bit mode is 0-01111111011-1001100110011001100110011001100110011001100110011010 when the actual storage;
3. The binary representation of 0.2 is 1.1001100110011001100110011001100110011001100110011001 1 (0011) + * 2^-3;
4. When the 64bit storage space cannot store the complete infinite loop decimals, and the IEEE 754 floating-point takes round to nearest, the tie to even rounding mode, Therefore 0.2 bit mode is 0-01111111100-1001100110011001100110011001100110011001100110011010 when the actual storage;
5. The actual stored bit pattern is used as the operand to add the floating-point number, resulting in 0-01111111101-0011001100110011001100110011001100110011001100110100. The conversion to decimal is 0.30000000000000004.
Why 0.7 * 180===125.99999999998?
1.0.7 the bit mode is 0-01111111110-0110011001100110011001100110011001100110011001100110 when actual storage;
2.180 the bit mode is 0-10000000110-0110100000000000000000000000000000000000000000000000 when actual storage;
3. The actual stored bit mode is used as the operand to multiply the floating-point number, resulting in 0-10000000101-1111011111111111111111111111111111111111101010000001. The conversion to decimal is 125.99999999998.
why 1000000000000000128 = = = 1000000000000000129 ?
1. 1000000000000000128 The bit mode of actual storage is 0-10000111010-1011110000010110110101100111010011101100100000000001;
2. 1000000000000000129 The bit mode of actual storage is 0-10000111010-1011110000010110110101100111010011101100100000000001;
3. Therefore1000000000000000128和1000000000000000129的实际存储的位模式是一样的。
Solution
We all understand that as long as the use of IEEE 754 FP's floating-point encoding language will be the problem, but their standard class library has provided us with a solution. And JS? Apparently not. The downside is that the hole is dropped, and the benefits are just the same:
For different application needs, we have different implementation methods.
Solution 0x00-simple Implementation
A simple operation for decimals and small integers can be used in the following ways
function Numadd (NUM1/*: String*/, num2/*: String*/) { varBasenum, BaseNum1, baseNum2; Try{baseNum1= Num1.split (".")[1].length; } Catch(e) {baseNum1=0; } Try{baseNum2= Num2.split (".")[1].length; } Catch(e) {baseNum2=0; } basenum= Math.pow (Ten, Math.max (BASENUM1, baseNum2)); return(NUM1 * basenum + num2 * basenum)/Basenum;};
Solution 0x01-math.js
If a complex and comprehensive computing function is required, it must be math.js, and its internal references are decimal.js and fraction.js. The function is exceptionally powerful and is used in the production environment properly!
Solution 0x02-d.js
D.js is my practiced hand project, as of this publication, the d.js version of V0.2.0, only implemented add, subtract, multiply and divide the operation, the bug is a heap of heap, but at least solve the problem of 0.1+0.2.
varsum = D.add (0.1,0.2) console.log (sum+"')//0.3varProduct = D.mul ("1e-2","2e-4") Console.log (product+"')//0.000002varquotient = D.Div (-3,2) Console.log (quotient+"')//-(1+1/2)
Problem Solving Ideas:
1. Because only the integers located between Number.min_safe_integer and Number.max_safe_integer can be accurately represented, that is, as long as the operands and the results of the operation are guaranteed to fall within this threshold, the result of the operation is accurate;
2. The crux of the problem is how to convert or split decimal and maximal numbers into the number of Number.min_safe_integer to Number.max_safe_integer thresholds;
3. Decimal conversion to an integer, which is naturally represented by scientific notation, and by the right to shift the decimal point, the way to reduce the power of processing; (e.g. 0.000123 equivalent to 123 * 10-6)
4. While the maximum number needs to be split, the rules for splitting are diverse.
4.1. Split by type: Assuming that 12345 is split to get 5 * 2469;
4.2. Bitwise split: Assume that 3 values for a set of 12345 are split to get 345 and 12, while the actual value is 12*1000 + 345.
As far as I am concerned, the 4.1 split rule structure is unstable and not intuitive, while the 4.2 rule is intuitive and the formula for splitting and recovering is fixed.
5. The remainder consists of the sign bit, the numerator, and the denominator, and the symbol is identical to the integer part, so you only need to consider how to represent the numerator and denominator.
6. The infinite loop number only needs to consider how to represent the loop number segment. (such as 10.2343434 is divided into 10.23 and the cycle number 34 and 34 weight can be)
Once the coding rules are obtained, there is a question of how to implement various operations based on the specified encoding.
1. Based on the above-mentioned numerical code rules how to achieve the addition and subtraction operation?
2. Based on the above-mentioned numerical code rules How to achieve multiplication, divide operation? (In fact, as long as the addition, reduction operations solved, multiplication must be solvable, is the problem of efficiency)
3. How do other mathematical operations, such as sin, tan, and%, be implemented based on the above-mentioned numerical coding rules?
In addition, because of the mathematical operations involved, it is necessary to keep variables such as add, Sub, mul, and div into parameters as pure as mathematical formulas (persistent/immutable Data Structure). Is it still going to introduce immutable.js? (D.js now uses a copy-on-demand approach, which can be expected to cause overall code to fail to maintain as the amount of code increases)
Conclusion
According to my urine sex, d.js will take a strategy that is not regularly updated (after I understand persistent/immutable Data structure:)). Welcome you to advise!
Respect the original, reprint please specify from: http://www.cnblogs.com/fsjohnhuang/p/5115672.html ^_^ fat son John
Thanks
Http://es5.github.io
https://github.com/MikeMcl/decimal.js/
Http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html
Http://demon.tw/copy-paste/javascript-precision.html
JS Magic Hall: A thorough understanding of 0.1 + 0.2 = = 0.30000000000000004 behind