關於javascript中對浮點加,減,乘,除的精度分析


   大學專業是計算機童鞋或多或小的知道 計算機是由二進制存儲和處理數字的,不能精確到處理浮點數,且javascript也沒有這樣的方法 所以在瀏覽器計算的時候也會有誤差,比如說 我想用 3.3 / 1.1  那么按道理來說 答案是 3 ,對不對 但是我們可以打印出來看下 結果令我們很驚訝 是 2.9999999999999996 .現在我們想 為了避免產生精度差異,需要計算的數字升級(乘以10的n次冪)成計算機能夠精確識別的整數,等計算完畢再降級(除以10的n次冪). 這樣處理下 就可以實現正常的結果。

基本原理:

   需要計算的數字升級(乘以10的n次冪)成計算機能夠精確識別的整數,等計算完畢再降級(除以10的n次冪). 這樣處理下 就可以實現正常的結果。

 Javascript 如何解決對 "加法" 精度問題

       其實不管對於 加法,減法 乘法及除法也好 其基本原理都是一樣 先乘以10的n次冪 成計算機能夠識別的整數 然后計算 計算完成后 再除以10的n次冪 這樣就可以得到想要的結果。

   現在我們先列舉個列子 比如:var a = 1.3, b = 2.3;那么 我通過在火狐瀏覽器打印一下console.log(a+b)=? 結果在火狐瀏覽器下看到等於:3.5999999999999996 .這也就是說計算機對浮點計算存在精度問題。而現在我們想寫個js函數方法,來避免這種情況的產生。

   函數的基本原理:先傳入2個參數 分別為arg1,arg2;先判斷下 如果2個參數都是浮點數的話 那么取得該2個參數的小數點后面的長度,分別保存到變量為firstArg,lastArg; 否則的話 如果那個參數不是浮點的話 那么讓此fisrtArg或者lastArg賦值為0. 然后取得差值 differ = Math.abs(firstArg - lastArg).(目的是為了下面判斷他們的小數點位數是否相同。) 接着獲取最大的n次冪 如: m = Math.pow(10,Math.max(firstArg,lastArg));

   1. 接着上面的話說,如果小數點后面的位數長度相同的話 比如說 1.3 和 2.3 小數點后的數字都是3,那么他們的長度都是相同的的(為1).那么先變為整數 去掉小數點后計算 如:arg1 = Number(arg1.toString().replace(".", ""));arg2 = Number(arg2.toString().replace(".", "")); 然后接着再除以他們的n次冪 如:return (arg1 + arg2) / m; 這樣可以返回結果。

   2. 如果小數點后面的位數長度不一致的話 先通過他們的差值 differ獲取n次冪 如:var dm = Math.pow(10,differ); 再判斷 如果 firstArg > lastArg 那么 arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")) * dm;否則的話 arg1 = Number(arg1.toString().replace(".", "")) * dm; arg2 = Number(arg2.toString().replace(".", "")); 再比如:var a = 1.31,b = 2.3; 那么 firstArg的長度為2 lastArg長度為1;因為 2 > 1 那么 arg1 = 131; arg2 = 23 * dm(如上:dm = Math.pow(10,differ));最后計算如:return (arg1 + arg2) / m --> (arg1 + arg2) / m  ---> (131 + 23*10) / Math.pow(10,Math.max(firstArg,lastArg)); --> 

 (131 + 230) / Math.pow(10,2) --> 361 / 100 = 3.61; 和1.31 + 2.3 結果一致。同理firstArg < lastArg也是一樣的原理。這里不多說了。

 為了更詳細的說明問題 我們可以先來看看流程圖:如下:

  

下面是JS函數代碼如下:

/**
 * js加法 解決精度問題
 */

 function addFun(arg1,arg2) {
    var firstArg,
        lastArg,
        differ,
        m;
    try{
        firstArg = arg1.toString().split('.')[1].length;
    }
    catch (e){
        firstArg = 0;
    }

    try{
        lastArg = arg2.toString().split('.')[1].length;
    }
    catch (e){
        lastArg = 0;
    }
    differ = Math.abs(firstArg - lastArg);
    m = Math.pow(10,Math.max(firstArg,lastArg));
    
    if(differ > 0) {
        var dm = Math.pow(10,differ);
        if(firstArg > lastArg) {
            arg1 = Number(arg1.toString().replace(".", ""));
            arg2 = Number(arg2.toString().replace(".", "")) * dm;

        }else {
            arg1 = Number(arg1.toString().replace(".", "")) * dm;
            arg2 = Number(arg2.toString().replace(".", ""));
        }
     }else {
        arg1 = Number(arg1.toString().replace(".", ""));
        arg2 = Number(arg2.toString().replace(".", ""));
    }
    return (arg1 + arg2) / m;
 }
View Code

 Javascript 如何解決對 "減法" 精度問題

  同樣現在我們先列舉個列子 比如:var a = 1.3, b = 2.3;那么 我通過在火狐瀏覽器打印一下console.log(b-a)=? 結果在火狐瀏覽器下看到等於:0.9999999999999998.同樣我們想寫個js函數方法,來避免這種情況的產生

代碼實現原理是:先傳入2個參數 分別為arg1,arg2;先判斷下 如果2個參數都是浮點數的話 那么取得該2個參數的小數點后面的長度,分別保存到變量為firstArg,lastArg; 否則的話 如果那個參數不是浮點的話 那么讓此fisrtArg或者lastArg賦值為0. 然后獲取他們的最大n次冪如:

differ = Math.pow(10, Math.max(firstArg, lastArg)); 接着如下判斷 如果firstArg的長度大於lastArg的長度 那么返回firstArg,否則返回lastArg; 如:m = (firstArg > lastArg) ? firstArg : lastArg;最后返回 return ((arg1 * differ - arg2 * differ) / differ).toFixed(m); 接着再列舉列子 比如還是上面 傳入a=2.3, b = 1.3 那么他們的長度相等(都為1) 即:differ = Math.pow(10,1);

m = lastArg = 1; 最后返回 ((arg1 * differ - arg2 * differ) / differ).toFixed(m) --> (2.3*10 - 1.3*10)/10.toFixed(1) = 1.0;

接着我們可以再列舉個反列:比如var b = 2.31, a = 1.3; 那么他們的長度不相等 即(b的小數點后面的長度為2 > a的小數點后面的長度1) 那么differ = Math.pow(10,Math(firstArg,lastArg)) -- > differ = Math.pow(10,2) --> differ = 100; m = firstArg = 2; 最后返回

((arg1*differ - arg2*differ)/differ).toFixed(m) --> (2.31*100 -1.3 * 100)/100.toFixed(2) = ((231-130)/100).toFixed(2) = 1.01; 和 b -a = 2.31 - 1.3 = 1.01結果相同 同樣推理正確。同樣我們來個簡單流程圖 如下:

 

下面是JS對減法解決精度的函數方法代碼如下:

/*
  * JS減法 解決精度問題
  */

  function subtraction(arg1,arg2){
     var firstArg,
         lastArg,
         differ,
         m;
     try{
        firstArg = arg1.toString().split('.')[1].length;
     }catch (e){
        firstArg = 0;
     }

     try{
        lastArg = arg2.toString().split('.')[1].length;
     }
     catch (e){
        lastArg = 0;
     }
     differ = Math.pow(10, Math.max(firstArg, lastArg));
     m = (firstArg > lastArg) ? firstArg : lastArg;
     return ((arg1 * differ - arg2 * differ) /    differ).toFixed(m);
  }
View Code

 Javascript 如何解決對 "乘法" 精度問題

     同樣現在我們先列舉個列子 比如:var a = 1.3, b = 2.3;那么 我通過在火狐瀏覽器打印一下console.log(a*b)=? 結果在火狐瀏覽器下看到等於:2.9899999999999998.但是實際的結果是:2.99 同樣我們想寫個js函數方法,來避免這種情況的產生.

  代碼的實現原理是:先傳入2個參數 分別為arg1,arg2,先把這2個參數轉化為字符串分別保存到firstArg和lastArg里面,如:

  firstArg = arg1.toString();lastArg = arg2.toString(); 接着定義個變量 m = 0;然后分別取到firstArg,lastArg的長度與m分別相加,如:m += firstArg.split('.')[1].length; m += lastArg.split('.')[1].length; 也就是說 m得到的就是 后面的小數點的位數。最后如下返回 return Number(firstArg.replace(".", "")) * Number(lastArg.replace(".", "")) / Math.pow(10, m);

  比如再列舉個列子 還是剛剛 a = 1.3, b = 2.3 來講,因為他們的firstArg和lastArg的長度都為1,也就是說 m = 2;那么返回

  Number(firstArg.replace(".", "")) * Number(lastArg.replace(".", "")) / Math.pow(10, m) ---> 

  Number(13 * 23)/Math.pow(10,2) = 13*23 / 100 = 2.99 與我們的1.3×2.3 = 2.99 結果相同。同理我們也可以隨便列舉列子都可以的,在這就不一一列舉哦!有興趣的童鞋可以多列舉下。

實現的JS代碼如下:

/**
   * JS乘法 解決精度問題
   */
  function multiplication(arg1,arg2) {
     var  m = 0,
         firstArg,
         lastArg;
     firstArg = arg1.toString();
     lastArg = arg2.toString();

     try{
        m += firstArg.split('.')[1].length;
     }
     catch (e){}

     try{
        m += lastArg.split('.')[1].length;
     }
     catch (e){}

     return Number(firstArg.replace(".", "")) * Number(lastArg.replace(".", "")) / Math.pow(10, m);
  }
View Code

 Javascript 如何解決對 "除法" 精度問題

    同樣現在我們先列舉個列子 比如:var a = 1.1, b = 3.3;那么 我通過在火狐瀏覽器打印一下console.log(b/a)=? 結果在火狐瀏覽器下看到等於:2.9999999999999996.但是實際的結果是:3 同樣我們想寫個js函數方法,來避免這種情況的產生.

    代碼實現的原理:先傳入2個參數 分別為arg1,arg2;先判斷下 如果2個參數都是浮點數的話 那么取得該2個參數的小數點后面的長度,分別保存到變量為firstArg,lastArg; 否則的話 如果那個參數不是浮點的話 那么讓此fisrtArg或者lastArg賦值為0. 接着把小數點都去掉分別進行相應的運算:如 r1 = Number(arg1.toString().replace(".", ""));r2 = Number(arg2.toString().replace(".", ""));

那么返回如下:return (r1 / r2) * Math.pow(10, lastArg - firstArg);就可以了。

 接着再列舉列子 比如var b = 3.3,a = 1.1 那么firstArg和lastArg的長度都為1,那么 r1 = Number(arg1.toString().replace(".", "")); --> r1 = 33; r2 = Number(arg2.toString().replace(".", "")); --> r2 = 11;那么 返回是:

 return (r1 / r2) * Math.pow(10, lastArg - firstArg); --> (33/11)×Math.pow(10,0) = 3.和我們想要等到的結果3.3/1.1=3是一樣的,說明推理正確。同樣我們可以列舉個其他的列子都ok的 具體的可以自己去列舉下 這里也不一一列舉了。

JS解決對"除法"精度問題的函數代碼如下:

 

/*
   * JS除法 解決精度問題
   */
  function division(arg1,arg2) {
     var firstArg,
         lastArg,
         r1,
         r2;
     
     try{
        firstArg = arg1.toString().split(".")[1].length;
     }
     catch (e){
        firstArg = 0; 
     }

     try{
        lastArg = arg2.toString().split('.')[1].length;
     }
     catch (e){
        lastArg = 0;
     }
      r1 = Number(arg1.toString().replace(".", ""));
      r2 = Number(arg2.toString().replace(".", ""));

      return (r1 / r2) * Math.pow(10, lastArg - firstArg);
  }
View Code

 

 

 


免責聲明!

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



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