2017-03-20 10:13

JavaScript 浮點數計算

一直一來都很少處理 JS 精準運算的問題,大部分的時候 UI 有點不準也不會造成太大的問題,這次用 JS 做一些加減的數字計算,遇到小數的時候就出現運算誤差,既然是 JS 計算機不精準是不行的,User 不可能接受的,找了一堆文章後沒一個靠譜的,但重點都是轉換到整數進行運算,再做浮點位移,整個計算最好盡量避免小數的處理,另外的問題就是位數不能太多。


  1. function transformInt(num1, num2, padZeno, compute) { 
  2.    num1 = '' + num1; 
  3.    num2 = '' + num2; 
  4.  
  5.    var p1 = 0, p2 = 0; 
  6.    try { p1 = num1.split(".")[1].length } catch (e) { } 
  7.    try { p2 = num2.split(".")[1].length } catch (e) { } 
  8.  
  9.    if(padZeno){ 
  10.        while (p1 < p2) { p1++; num1 += '0'; } 
  11.        while (p2 < p1) { p2++; num2 += '0'; } 
  12.    } 
  13.  
  14.    var int1 = parseInt(num1.replace(".", ""), 10); 
  15.    var int2 = parseInt(num2.replace(".", ""), 10); 
  16.    return compute(int1, int2, p1, p2); 
  17. } 
  18.  
  19.  
  20. /*浮點數相加*/ 
  21. function floatAdd(num1, num2) { 
  22.    return transformInt(num1, num2, true, function(int1, int2, p1, p2){ 
  23.        return (int1 + int2) / Math.pow(10, p1); 
  24.    }); 
  25. } 
  26.  
  27. /*浮點數相減*/ 
  28. function floatSub(num1, num2) { 
  29.    return transformInt(num1, num2, true, function(int1, int2, p1, p2){ 
  30.        return (int1 - int2) / Math.pow(10, p1); 
  31.    }); 
  32. } 
  33.  
  34. /*浮點數相乘*/ 
  35. function floatMul(num1, num2) { 
  36.    return transformInt(num1, num2, false, function(int1, int2, p1, p2){ 
  37.        return (int1 * int2) / Math.pow(10, p1 + p2); 
  38.    }); 
  39. } 
  40.  
  41. /*浮點數相除*/ 
  42. function floatDiv(num1, num2) { 
  43.    return transformInt(num1, num2, false, function(int1, int2, p1, p2){ 
  44.        return (int1 / int2) / Math.pow(10, p1 - p2); 
  45.    }); 
  46. } 
  47.  
  48.  
  49.  
  50. function unitTest(method, list){ 
  51.    console.log('=[ ' + method.name + ' ]=============================================='); 
  52.  
  53.    for (var i = 0; i < list.length; i++){ 
  54.        var row = list[i]; 
  55.        var result = method(row.num1, row.num2); 
  56.  
  57.        if(result == row.ans){ 
  58.            console.log(row, result); 
  59.        }else{ 
  60.            console.error(row, result); 
  61.        } 
  62.    }; 
  63. } 
  64.  
  65. unitTest(floatAdd, [ 
  66.    {num1:0.11, num2:0.2, ans: 0.31}, 
  67.    {num1:0.21, num2:0.2, ans: 0.41}, 
  68.    {num1:0.31, num2:0.2, ans: 0.51}, 
  69.    {num1:0.41, num2:0.2, ans: 0.61}, 
  70.    {num1:0.51, num2:0.2, ans: 0.71}, 
  71.    {num1:0.61, num2:0.2, ans: 0.81}, 
  72.    {num1:0.71, num2:0.2, ans: 0.91}, 
  73.    {num1:0.81, num2:0.2, ans: 1.01}, 
  74.    {num1:0.91, num2:0.2, ans: 1.11}, 
  75.    {num1:1.01, num2:0.2, ans: 1.21}, 
  76. ]); 
  77.  
  78. unitTest(floatSub, [ 
  79.    {num1:1.02, num2:0.2, ans: 0.82}, 
  80.    {num1:1.12, num2:0.2, ans: 0.92}, 
  81.    {num1:1.22, num2:0.2, ans: 1.02}, 
  82.    {num1:1.32, num2:0.2, ans: 1.12}, 
  83.    {num1:1.42, num2:0.2, ans: 1.22}, 
  84.    {num1:1.52, num2:0.2, ans: 1.32}, 
  85.    {num1:1.62, num2:0.2, ans: 1.42}, 
  86.    {num1:1.72, num2:0.2, ans: 1.52}, 
  87.    {num1:1.82, num2:0.2, ans: 1.62}, 
  88.    {num1:1.92, num2:0.2, ans: 1.72}, 
  89. ]); 
  90.  
  91. unitTest(floatMul, [ 
  92.    {num1:10, num2:0.14, ans: 1.4}, 
  93.    {num1:10, num2:0.24, ans: 2.4}, 
  94.    {num1:10, num2:0.34, ans: 3.4}, 
  95.    {num1:10, num2:0.44, ans: 4.4}, 
  96.    {num1:10, num2:0.54, ans: 5.4}, 
  97.    {num1:10, num2:0.64, ans: 6.4}, 
  98.    {num1:10, num2:0.74, ans: 7.4}, 
  99.    {num1:10, num2:0.84, ans: 8.4}, 
  100.    {num1:10, num2:0.94, ans: 9.4}, 
  101.    {num1:10, num2:1.04, ans: 10.4}, 
  102. ]); 
  103.  
  104. unitTest(floatDiv, [ 
  105.    {num1:1.1, num2:0.1, ans: 11}, 
  106.    {num1:1.1, num2:0.2, ans: 5.5}, 
  107.    {num1:0.99, num2:0.3, ans: 3.3}, 
  108.    {num1:1.1, num2:0.4, ans: 2.75}, 
  109.    {num1:1.1, num2:0.5, ans: 2.2}, 
  110.    {num1:1.32, num2:0.6, ans: 2.2}, 
  111.    {num1:1.54, num2:0.7, ans: 2.2}, 
  112.    {num1:1.76, num2:0.8, ans: 2.2}, 
  113.    {num1:2.97, num2:0.9, ans: 3.3}, 
  114.    {num1:1.1, num2:0.1, ans: 11}, 
  115. ]);