js + 0.1 0.2! == 0.3

1. Storage principle:

Either fixed-point or floating-point numbers are based on a number of binary manner is stored in the digital computer.
In fact not just Javascript, in many languages will get .30000000000000004 0.1 + 0.2, this also gave birth to a fun site  .30000000000000004 . In essence, these figures are based on the language IEEE 754 64-bit double-precision floating-point  store, which is composed of 64 bits, which consists of three parts 64, (S: sign bit, Exponent: exponent field, Fraction : mantissa field). It is represented in the format:

 

 

 

 

s is the sign bit indicates positive or negative. m is the mantissa, there  52 is  bits. e is the exponent, there  . 11  bits, is e in the range  [-1074, 971] ( the ECMAScript specification. 5 ), so that in fact it is easy to launch the maximum number that can be represented as Javascript:

1 * (Math.pow(2, 53) - 1) * Math.pow(2, 971) = 1.7976931348623157e+308

And this number is the  Number.MAX_VALUE value.

The same can be deduced  Number.MIN_VALUE values:

1 * 1 * Math.pow(2, -1074) = 5e-324

It should be noted, Number.MIN_VALUE represents the smallest of the large number of nil , rather than the minimum number, the smallest number is clearly -Number.MAX_VALUE.

You may have noticed that when the calculation  Number.MAX_VALUE , the (Math.pow(2, 53) - 1) result is a binary representation  53  Items 1, in addition to 52 bits m represents, in fact, the foremost of 1 bit is hidden bit (always a hidden bit representation of 1), set the hidden bits that can represent a number greater range. (Hiding place was not very clear for me, one said, "When exponent e bits are all 0, the hidden bit is 0, if not all zeros, then the hidden bit is 1, it should be based on storage index expressions decision, hide-bit integer that is part of the inside of the base number exponent, mantissa m is the fraction fractional part of the index base could "see  the accuracy of Javascript number of small and large integers loss problems )

After reviewing some knowledge of composition principle, we go back to 0.1 + 0.2 This question itself. As we all know, digital computer are stored in binary is , if the calculation result to the 0.1 + 0.2, 0.1 and 0.2 computers are first converted to binary, and then the addition result obtained by adding and then finally converted to decimal.

We put 0.1 and 0.2 respectively converted into binary, decimal into binary here is not to say, the integer part "in addition to more than two takes, in reverse order," the fractional part "by two rounded, order." Javascript can also be used to  toString(2)verify the result of the conversion method.

// 0.1 is converted to a binary 
0.0 0011 0011 0011 0011 ... (0011 cycles) 

// 0.2 converted to binary 
0.0011 0011 0011 0011 0011 ... (0011 cycles)

Of course, the computer does not represent an infinite decimal, after all, only limited resources, so we have to put them in  IEEE 754 double-precision 64-bit floating-point numbers  to represent:

-4 = E; m = 1.1001100110011001100110011001100110011001100110011010 (52 is bits) 
E = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52 is bit)

Of course, the real computer and does not store m is a decimal, but above 52 bits after the decimal point, before the decimal point is a hidden bit .

Here again there is a problem, although we have made it clear there can be only 52 m (after the decimal point), but if the 53 bit is 1, is the carry or not to carry? 754 It should be considered the IEEE  a Rounding Modes , you can look at this article  float doubts , or simply listen to me explain.

About the default rounding rule, simply put, if 1.101 to one decimal, possible values ​​are 1.1 and 1.2, 1.101 and then look at the value of 1.1 or 1.2 which is closer, no doubt is 1.1, then the answer is 1.1 . So if you want to keep it to two decimal places? Obviously either 1.10 or 1.11, and has nearly the same, then we should look at what these two numbers is an even number (the last one is even), leave an even number as the answer. In summary, if the first 52 bit and 53 bit is 1, it is to get into bits.

In addition, if the index adding inconsistencies need to be aligned, it is generally to the right, because even if the rightmost overflow, loss of accuracy is much smaller than the left overflow.

Next it is not difficult:

-4 = E; m = 1.1001100110011001100110011001100110011001100110011010 (52 is bits)
 + E = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52 is bit)
 ------------------------- -------------------------------------------------- 
  E = -3; m = 0.1100110011001100110011001100110011001100110011001101 
+ E = -3; m = 1.1001100110011001100110011001100110011001100110011010 
--------------------------------- ------------------------------------------ 
  E = -3; m = 10.0110011001100110011001100110011001100110011001100111 
-------------------------------------------------- ------------------------- 
  E = -2; m = 1.0011001100110011001100110011001100110011001100110100 (52 is bit)
-------------------------------------------------- ------------------------- 
= 0.010011001100110011001100110011001100110011001100110100 
= 0.30000000000000004 (decimal)

The  9007199254740992 + 1 = 9007199254740992 reasoning is similar.

9007199254740992 is actually 2 ^ 53.

0 = E; m = 100000000000000000000000000000000000000000000000000000 (th 53 is 0)
 + E = 0; m =. 1 
------------------------------ --------------------------------------------- 
  E = 0; m = 100000000000000000000000000000000000000000000000000001

Because there are only 52 m, while the upper two numbers together after the addition of 53 m (hidden first bit has been removed), and because  Rounding modes  even number of principles, so that the 53 bit rounding 1, so about the size of 2 ^ 52 does not change, Imagine, if + 2, then the result is not the same. (Ps: in fact 2 ^ 53 m in a computer store 52 only, i.e. only 52 0)

In fact, when the result is greater than Math.pow (2, 53), there will be loss of precision, resulting in the final result there is a deviation, and when the result is greater than Number.MAX_VALUE, return directly Infinity.

2. Solution:

1. Only for fractional arithmetic (with bug):

// solve dimensional calculation, js calculated lose precision problem 

// adder    
Number.prototype.add = function (Arg) {   
     var R1, R2, m;   
     the try {R1 = the this . .ToString () Split ( ".") [ . 1]} .length the catch (E) R1 = {0 }   
     the try {arg.toString R2 = (). Split ( ".") [. 1]} .length the catch (E) R2 = {0 }    
    m = Math.pow (10 , Math.max (R1, R2))   
     return ( the this * Arg * m + m) / m   
 }     
 // subtractor    
Number.prototype.sub = function (Arg) {   
     return  the this .add (-arg);   
}   
//乘法   
Number.prototype.mul = function (arg)   
{   
    var m=0,s1=this.toString(),s2=arg.toString();   
    try{m+=s1.split(".")[1].length}catch(e){}   
    try{m+=s2.split(".")[1].length}catch(e){}   
    return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)   
}  
//除法   
Number.prototype.div = function (arg){   
    var t1=0,t2=0,r1,r2;   
    try{t1=this.toString().split(".")[1].length}catch(e){}   
    try{t2=arg.toString().split(".")[1].length}catch(e){}   
    with(Math){   
        r1=Number(this.toString().replace(".",""))   
        r2=Number(arg.toString().replace(".",""))   
        return (r1/r2)*pow(10,t2-t1);   
    }   
} 
0.1+0.2  // 0.30000000000000004
0.1.add(0.2)  //0.3
0.3-0.1  //0.19999999999999998
0.3.sub(0.1)  //0.2

2. The introduction of some ready library, such math.js or  bigNumber.js , decimal.js , big.js  the like;

Guess you like

Origin www.cnblogs.com/momo798/p/11649147.html