[ JS 基礎 ] JS 浮點數四則運算精度丟失問題 (3)

基於這個問題:javascript運動基礎問題 ,我想應該也有一部分人沒有認真對待過js中浮點數的四則運算出現的問題。javascript

1.問題描述

示例代碼:
    var x  = 0.3 - 0.2; //30美分減去20美分
    var y =  0.2 - 0.1; //20美分減去10美分
    x == y;             // =>false,兩值不相等
    x == 0.1;           // =>false,真實值爲:0.09999999999999998
    y == 0.1;           // =>true
    這個問題並不僅是在Javascript中才會出現,任何使用二進制浮點數的編程語言都會有這個問題,只不過在 C++/C#/Java 這些語言中已經封裝好了方法來避免精度的問題,而 JavaScript 是一門弱類型的語言,從設計思想上就沒有對浮點數有個嚴格的數據類型,因此精度偏差的問題就顯得格外突出。

2.產生緣由

Javascript採用了IEEE-745浮點數表示法(幾乎全部的編程語言都採用),這是一種二進制表示法,能夠精確地表示分數,好比1/2,1/8,1/1024。遺憾的是,咱們經常使用的分數(特別是在金融的計算方面)都是十進制分數1/10,1/100等。二進制浮點數表示法並不能精確的表示相似0.1這樣 的簡單的數字,上訴代碼的中的x和y的值很是接近最終的正確值,這種計算結果能夠勝任大多數的計算任務:這個問題也只有在比較兩個值是否相等時纔會出現。
javascript的將來版本或許會支持十進制數字類型以免這些舍入問題,在這以前,你更願意使用大整數進行重要的金融計算,例如,要使用整數‘分’而不是使用小數‘元’進行貨比單位的運算---------以上整理自《Javascript權威指南P37》java

3. 0.1+0.2的計算

首先,咱們要站在計算機的角度思考 0.1 + 0.2 這個看似小兒科的問題。咱們知道,能被計算機讀懂的是二進制,而不是十進制,因此咱們先把 0.1 和 0.2 轉換成二進制看看:
0.1 => 0.0001 1001 1001 1001…(無限循環)
0.2 => 0.0011 0011 0011 0011…(無限循環)
雙精度浮點數的小數部分最多支持 52 位,因此二者相加以後獲得這麼一串 0.0100110011001100110011001100110011001100110011001100 因浮點數小數位的限制而截斷的二進制數字,這時候,咱們再把它轉換爲十進制,就成了 0.30000000000000004。編程

4.解決方案 (引自:解決方案

爲了解決浮點數運算不許確的問題,在運算前咱們把參加運算的數先升級(10的X的次方)到整數,等運算完後再降級(0.1的X的次方)。segmentfault

//加法   
    Number.prototype.add = function(arg){   
        var r1,r2,m;   
        try{r1=this.toString().split(".")[1].length}catch(e){r1=0}   
        try{r2=arg.toString().split(".")[1].length}catch(e){r2=0}   
        m=Math.pow(10,Math.max(r1,r2))   
        return (this*m+arg*m)/m   
    }  
    //減法   
Number.prototype.sub = function (arg){   
    return 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);   
    }   
}

ok,就是這樣了,你們之後在本身的代碼中遇到浮點數要想起js運算的這樣的一個特性,避免沒必要要的錯誤!編程語言

相關文章
相關標籤/搜索