Recently developed new project demand, need a amount of input box, the maximum input for 16 bit integer with two decimal floating point types, due to the amount shown at the front desk is a string type, when passed to the background using the parseFloat () method, but found in the test check critical value, the largest round, eventually leading to failure check, This triggered my deep understanding of THE REPRESENTATION and operation of JS floating-point numbers.
JS floating point number precision loss
Some numbers cannot be represented finitely due to the binary implementation and bit limits of computers. Just like some irrational numbers cannot be expressed in a finite way, such as PI 3.1415926… , 1.3333… And so on. JS complies with IEEE 754 specification, adopts double precision storage, occupying 64 bit.
- The 1 bit is used to represent the sign bit
- The 11 digits are used to indicate the exponent
- 52 digits indicate the mantissa
Because at the bottom of the computer, numerical operations and operations are implemented in binary, so the computer can not accurately represent floating point numbers, and can only use binary approximately equal to represent the decimal part of floating point numbers.
0.1 >> 0.0001 1001 1001 1001... (1001 infinite loop) 0.2 >> 0.0011 0011 0011 0011... (0011 Infinite loop)Copy the code
When performing calculations or other operations, rounding (1, 0) will result in a deviation in the final result.
The same problem exists with large integers, because the mantissa representing the mantissa is only 52 bits, so the largest integer that can be accurately represented in JS is math.pow (2, 53), which is the decimal 9007199254740992.
9007199254740992 > > 10000000000000... 000 // total 53 0 9007199254740992 + 1 >> 10000000000000... 001 // Middle 52 0 9007199254740992 + 2 >> 10000000000000... 010 // Middle 51 0 9007199254740992 + 1 // Lost //9007199254740992 9007199254740992 + 2 // Not lost //9007199254740994 9007199254740992 + 3 // Lost //9007199254740992 9007199254740992 + 4 // Not lost //9007199254740996Copy the code
It can be seen from this that there are finite values in the decimal system, which may be infinite values of 0 and 1 cycles at the bottom of the computer.
In Java, C, and C++, there are special treatments for floating-point values, such as Java’s BigDecimal type to solve this floating-point problem.
Common places where things go wrong
Floating point calculation and comparison:
0.1 + 0.2! = 0.3 / /true
Copy the code
Large integer calculation and comparison:
Ordinary integer calculations are less error-prone unless the calculation extends beyond math.pow (2, 53)
= = 10000000000000001/9999999999999999 /true
Copy the code
Multi-digit character numeric conversion:
This situation in some amount of calculation is easier to appear, but also the most easily overlooked a, when the user to enter a number in the input box more string (not just contains large numerical digits after the decimal point are also included in this case), and at the front desk to use JS converts it to a numerical value, the result often is rounded with a deviation value
The parseFloat (0.9); / / / / 0.9 parseFloat (9999999999999999.9) 10000000000000000 parseInt ("9999999999999999"); / / 10000000000000000 parseFloat (9.999999999999999); / / 10Copy the code
ToFixed does not round:
Var num = 1.335; num.toFixed(2); / / 1.33Copy the code
The solution
Floating point calculation and comparison:
This problem is usually solved by converting the floating point part to an integer and evaluating it
// Float is converted to an integerfunction toInt(num){
var rel = {};
var str,pos,len,times;
str = (num < 0) ? -num + ' ' : num + ' ';
pos = str.indexOf('. ');
len = str.substr(pos+1).length;
times= Math.pow(10, len+1); // Add: when the number of decimal places is large, to avoid error, so more than double, improve precision rel. Times =times;
rel.num = num;
returnrel; } // The calculation processfunction operate(a,b,op){
var d1 = toInt(a);
var d2 = toInt(b);
var max = d1.times > d2.times ? d1.times : d2.times;
var rel;
switch(op){
case "+" :
rel = (d1.num * max + d2.num * max) / max;
break;
case "-" :
rel = (d1.num * max - d2.num * max) / max;
break;
case "*" :
rel = ((d1.num * max) * (d2.num * max)) / (max * max);
break;
case "/" :
rel = (d1.num * max) / (d2.num * max);
break;
}
return rel;
}
var rel = operate(0.3,0.1,"+"); / / 0.4Copy the code
Multi-digit numerical conversion:
The foreground does not carry out numerical conversion of this kind of string. After being transmitted to the background, it is processed by the background
ToFix fixes:
function toFixed(num, s) {
var times = Math.pow(10, s)
var des = num * times + 0.5
des = parseInt(des, 10) / times
return des + ' '
}
Copy the code