如何避免Javascript浮点计算精度问题

1     var num1 = 0.1, num2 = 0.2;
2     console.log(num1 + num2) // 0.30000000000000004

由于计算机内部的信息都是由二进制方式表示的,即0和1组成的各种编码,但由于某些浮点数没办法用二进制准确的表示出来。

1     var num1 = 0.1, num2 = 0.2;
2     console.log(num1.toString(2)) // 0.0001100110011001100110011001100110011001100110011001101
3     console.log(num2.toString(2)) // 0.001100110011001100110011001100110011001100110011001101

规避浮点计算

 1     var handleAdd = function(num1, num2) {
 2         num1 = Number(num1);
 3         num2 = Number(num2);
 4         var dec1, dec2, times;
 5         try { dec1 = countDecimals(num1)+1; } catch (e) { dec1 = 0; }
 6         try { dec2 = countDecimals(num2)+1; } catch (e) { dec2 = 0; }
 7         times = Math.pow(10, Math.max(dec1, dec2));
 8         var result = (handleMul(num1, times) + handleMul(num2, times)) / times;
 9         return result;
10     };
11     
12     var handleSub = function(num1, num2) {
13         num1 = Number(num1);
14         num2 = Number(num2);
15         var dec1, dec2, times;
16         try { dec1 = countDecimals(num1)+1; } catch (e) { dec1 = 0; }
17         try { dec2 = countDecimals(num2)+1; } catch (e) { dec2 = 0; }
18         times = Math.pow(10, Math.max(dec1, dec2));
19         var result = Number((handleMul(num1, times) - handleMul(num2, times)) / times);
20         return result;
21     };
22     
23     var handleDiv = function(num1, num2) {
24         num1 = Number(num1);
25         num2 = Number(num2);
26         var t1 = 0, t2 = 0, dec1, dec2;
27         try { t1 = countDecimals(num1); } catch (e) { }
28         try { t2 = countDecimals(num2); } catch (e) { }
29         dec1 = convertToInt(num1);
30         dec2 = convertToInt(num2);
31         var result = handleMul((dec1 / dec2), Math.pow(10, t2 - t1));
32         return result
33     };
34     
35     var handleMul = function(num1, num2) {
36         num1 = Number(num1);
37         num2 = Number(num2);
38         var times = 0, s1 = num1.toString(), s2 = num2.toString();
39         try { times += countDecimals(s1); } catch (e) { }
40         try { times += countDecimals(s2); } catch (e) { }
41         var result = convertToInt(s1) * convertToInt(s2) / Math.pow(10, times);
42         return result
43     };
44     
45     var countDecimals = function(num) {
46         var len = 0;
47         try {
48             num = Number(num);
49             var str = num.toString().toUpperCase();
50             if (str.split('E').length === 2) { // scientific notation
51                 var isDecimal = false;
52                 if (str.split('.').length === 2) {
53                     str = str.split('.')[1];
54                     if (parseInt(str.split('E')[0]) !== 0) {
55                         isDecimal = true;
56                     }
57                 }
58                 let x = str.split('E');
59                 if (isDecimal) {
60                     len = x[0].length;
61                 }
62                 len -= parseInt(x[1]);
63             } else if (str.split('.').length === 2) { // decimal
64                 if (parseInt(str.split('.')[1]) !== 0) {
65                     len = str.split('.')[1].length;
66                 }
67             }
68         } catch(e) {
69             throw e;
70         } finally {
71             if (isNaN(len) || len < 0) {
72                 len = 0;
73             }
74             return len;
75         }
76     };
77     
78     var convertToInt = function(num) {
79         num = Number(num);
80         var newNum = num;
81         var times = countDecimals(num);
82         var temp_num = num.toString().toUpperCase();
83         if (temp_num.split('E').length === 2) {
84             newNum = Math.round(num * Math.pow(10, times));
85         } else {
86             newNum = Number(temp_num.replace(".", ""));
87         }
88         return newNum;
89     };
90     console.log(handleAdd(0.1, 0.2)) // 0.3
91     console.log(handleSub(1, 0.2)) // 0.8
92     console.log(handleDiv(2.3, 10)) // 0.23
93     console.log(handleMul(1.7, 10)) // 17

 

精度的思路: 将要进行计算的数值转化为整数进行计算,再将计算结果转化为小数。

posted on 2019-02-21 10:59  时光游弋  阅读(783)  评论(0编辑  收藏  举报