js 浮點數加減總結


https://blog.csdn.net/qinshenxue/article/details/43671763

說明
眾所周知,js在計算浮點數時候,結果可能會不准確。比如:(在chrome中的運算結果) 
2.2 + 2.1 = 4.300000000000001 
2.2 - 1.9 = 0.30000000000000027 
2.2 * 2.2 = 4.840000000000001 
2.1 / 0.3 = 7.000000000000001

網上流傳的代碼(有bug)
網上流傳的優化后的代碼如下(有問題的代碼,請勿使用)

function add(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (a * e + b * e) / e;
}

function sub(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (a * e - b * e) / e;
}

function mul(a, b) {
    var c = 0,
        d = a.toString(),
        e = b.toString();
    try {
        c += d.split(".")[1].length;
    } catch (f) {}
    try {
        c += e.split(".")[1].length;
    } catch (f) {}
    return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}

function div(a, b) {
    var c, d, e = 0,
        f = 0;
    try {
        e = a.toString().split(".")[1].length;
    } catch (g) {}
    try {
        f = b.toString().split(".")[1].length;
    } catch (g) {}
    return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), c / d * Math.pow(10, f - e);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
原理就是將浮點數轉化為整數來計算。

問題代碼測試
但是上面的優化方法真的解決問題了嗎,我們可以簡單做下測試。 
測試代碼如下:(測試運算中加法)

function test(){
    var a = (Math.random() * 100).toFixed(2) - 0;
    var b = (Math.random() * 1000).toFixed(2) - 0;
    var result = add(a, b);
    if ((result + '').length > 10) {
        console.error('被加數:'+a,'加數:'+b, '結果:'+result);
        return;
    }
    setTimeout(function() {
        test();
    }, 10);
}
test();
1
2
3
4
5
6
7
8
9
10
11
12
13
問題代碼測試結果
瀏覽器控制台很快就打印了結果,說明被測試的加法運算代碼存在運算不准確的問題。 
測試運行結果: 


問題代碼出錯原因
既然上面的代碼有問題,那么出錯的點在哪里,我們就以計算錯誤的數字來調試代碼。 
被加數:19.36 加數:601.19 結果:620.5500000000001 
調試的過程及結果如下: 

我們發現原來是其中的乘法計算錯誤。

修正方法
網上有一些版本你會發現在最終返回結果的時候加上了toFixed,這是一種解決方法。 
另外既然是乘法出錯,我們何不將乘法換成優化后的乘法了。比如修改后的加法如下:

function add(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
然后用上面的方法進行測試,等了”一天“,控制台也沒打印了。說明這次真的把問題解決了。

最終版(正確版)
function add(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
}

function sub(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e;
}

function mul(a, b) {
    var c = 0,
        d = a.toString(),
        e = b.toString();
    try {
        c += d.split(".")[1].length;
    } catch (f) {}
    try {
        c += e.split(".")[1].length;
    } catch (f) {}
    return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}

function div(a, b) {
    var c, d, e = 0,
        f = 0;
    try {
        e = a.toString().split(".")[1].length;
    } catch (g) {}
    try {
        f = b.toString().split(".")[1].length;
    } catch (g) {}
    return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), mul(c / d, Math.pow(10, f - e));
}
--------------------- 
作者:筆心 
來源:CSDN 
原文:https://blog.csdn.net/qinshenxue/article/details/43671763 
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM