JS 計算問題


問題這樣的: 
37.5*5.5=206.08 (JS算出來是這樣的一個結果,我四舍五入取兩位小數) 
我先懷疑是四舍五入的問題,就直接用JS算了一個結果為:206.08499999999998 
怎么會這樣,兩個只有一位小數的數字相乘,怎么可能多出這么小數點出來。 
我Google了一下,發現原來這是JavaScript浮點運算的一個bug。 
比如:7*0.8 JavaScript算出來就是:5.6000000000000005 
網上找到了一些解決辦法,就是重新寫了一些浮點運算的函數。 
下面就把這些方法摘錄下來,以供遇到同樣問題的朋友參考: 

程序代碼 

//除法函數,用來得到精確的除法結果 
//說明:javascript的除法結果會有誤差,在兩個浮點數相除的時候會比較明顯。這個函數返回較為精確的除法結果。 
//調用:accDiv(arg1,arg2) 
//返回值:arg1除以arg2的精確結果 

function accDiv(arg1,arg2){ 
  var t1=0,t2=0,r1,r2; 
  try{t1=arg1.toString().split(".")[1].length}catch(e){} 
  try{t2=arg2.toString().split(".")[1].length}catch(e){} 
  with(Math){ 
    r1=Number(arg1.toString().replace(".","")) 
    r2=Number(arg2.toString().replace(".","")) 
    return (r1/r2)*pow(10,t2-t1); 
  } 
} 

 

//乘法函數,用來得到精確的乘法結果 
//說明:javascript的乘法結果會有誤差,在兩個浮點數相乘的時候會比較明顯。這個函數返回較為精確的乘法結果。 
//調用:accMul(arg1,arg2) 
//返回值:arg1乘以arg2的精確結果 

function accMul(arg1,arg2) { 
  var m=0,s1=arg1.toString(),s2=arg2.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) 
} 


//加法函數,用來得到精確的加法結果 
//說明:javascript的加法結果會有誤差,在兩個浮點數相加的時候會比較明顯。這個函數返回較為精確的加法結果。 
//調用:accAdd(arg1,arg2) 
//返回值:arg1加上arg2的精確結果 

function accAdd(arg1,arg2){ 
  var r1,r2,m; 
  try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} 
  try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} 
  m=Math.pow(10,Math.max(r1,r2)) 
  return (arg1*m+arg2*m)/m 
} 

 

帖出減法的代碼:

function Subtr(arg1,arg2){
     var r1,r2,m,n;
     try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
     try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
     m=Math.pow(10,Math.max(r1,r2));
     //last modify by deeka
     //動態控制精度長度
     n=(r1>=r2)?r1:r2;
     return ((arg1*m-arg2*m)/m).toFixed(n);
}

 

 

//乘法函數,用來得到精確的乘法結果 
//說明:javascript的乘法結果會有誤差,在兩個浮點數相乘的時候會比較明顯。這個函數返回較為精確的乘法結果。 
//調用:accMul(arg1,arg2) 
//返回值:arg1乘以arg2的精確結果 
function accMul(arg1,arg2) 
{ 
    var m=0,s1=arg1.toString(),s2=arg2.toString(); 
    try{
        if(s1.split(".")[1] != undefined )
            m+=s1.split(".")[1].length
    }catch(e){} 
    try{
        if(s2.split(".")[1] != undefined )
            m+=s2.split(".")[1].length
    }catch(e){} 
    return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m) 
} 
  
//浮點數除法運算  
 function accDiv(arg1,arg2){   
    var r1=0,r2=0,m,s1=arg1.toString(),s2=arg2.toString();  
    try{
        if(s1.split(".")[1] != undefined )
            r1=s1.split(".")[1].length;
    }catch(e){} 
    try{
        if(s2.split(".")[1] != undefined )
            r2=s2.split(".")[1].length;
    }catch(e){} 
    m=Math.pow(10,Math.max(r1,r2));   
    return (accMul(arg1,m))/(accMul(arg2,m));   
}   

function accAdd(arg1,arg2){ 
    var r1=0,r2=0,m,s1=arg1.toString(),s2=arg2.toString();  
    try{
        if(s1.split(".")[1] != undefined )
            r1=s1.split(".")[1].length;
    }catch(e){} 
    try{
        if(s2.split(".")[1] != undefined )
            r2=s2.split(".")[1].length;
    }catch(e){} 
    m=Math.pow(10,Math.max(r1,r2)); 
    return (accMul(arg1,m)+accMul(arg2,m))/m; 
} 

function Subtr(arg1,arg2){
     var r1=0,r2=0,m,n,s1=arg1.toString(),s2=arg2.toString();
     try{
         if(s1.split(".")[1] != undefined )
             r1=s1.split(".")[1].length;
     }catch(e){}
     try{
         if(s2.split(".")[1] != undefined )
             r2=s2.split(".")[1].length;
     }catch(e){}
     m=Math.pow(10,Math.max(r1,r2));
     //last modify by deeka
     //動態控制精度長度
     n=(r1>=r2)?r1:r2;
     return (accMul(arg1,m)-accMul(arg2,m))/m;
}

 

附js方法解釋

pow 方法

返回底表達式的指定次冪。

Math.pow(base, exponent)

參數

base

必選項。表達式底的值。

exponent

必選項。表達式的指數值。

示例

在下面的例子中,等同於 baseexponent數值表達式,返回值為 1000。

Math.pow(10,3);

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Javascript四舍五入(Math.round()與Math.pow())</title>
<script type="text/javascript">
  //Math.round(x);返回數字最接近的整數,四舍五入取整數,即舍去小數部分
  function f(){
    alert(Math.round(123.567));
    alert(Math.round(123.456));
  }
  //Math.pow(x,y);返回底數的指定次冪
  //返回以x的y次冪,等同於x的y次冪的數值表達式
  //如果pow的參數過大而引起浮點溢出,返回Infinity
  function f1(){
    alert(Math.pow(2,10));//2的10次方等於1024
    alert(Math.pow(1024,0.1));//1024的0.1次方等於2
    alert(Math.pow(99,9999));//溢出則返回Infinity
  }
  /*Javascript設置要保留的小數位數,四舍五入。
  *ForDight(Dight,How):數值格式化函數,Dight要格式化的 數字,How要保留的小數位數。
  *這里的方法是先乘以10的倍數,然后去掉小數,最后再除以10的倍數。
  */ 
  function ForDight(Dight,How){ 
    Dight = Math.round(Dight*Math.pow(10,How))/Math.pow(10,How); 
    return Dight; 
  } 
  function f2(){
    alert(ForDight(12345.67890,3));//保留三位小數
    alert(ForDight(123.99999,4));//保留四位小數
  }
  //另外一種四舍五入的方法,原理一樣。
  //里面的兩個參數:num就是要轉換的數據。n為要轉換的位數
  //cheng(123.456,2);//保留兩位小數
  function cheng(num,n){
    var dd=1; 
    var tempnum; 
    for(i=0;i<n;i ){
      dd*=10; 
    } 
    tempnum = num*dd;
    tempnum = Math.round(tempnum); 
    alert(tempnum/dd); 
  }
</script>
</head>
<body>
<input type="button" value="round" onclick="f();" />
<input type="button" value="pow" onclick="f1();" />
<input type="button" value="設置要保留的小數位數,四舍五入" onclick="f2();" />
<input type="button" value="cheng" onclick="cheng(123.456,2);" />
</body>
</html>
其它實現方法參考:
<script type="text/javascript">
  //用Javascript取float型小數點后兩位,例22.127456取成22.13,如何做? 
  //1.最笨的辦法....... [我就怎么干的.........] 
  function get(){
    var s = 22.127456 "";
  var str = s.substring(0,s.indexOf(".") 3);
    alert(str);
  } 
</script>
<script type="text/javascript">
  //2. 正則表達式效果不錯 
  onload = function(){
    var a = "23.456322";
    var aNew;
    var re = /([0-9] \.[0-9]{2})[0-9]*/;
    aNew = a.replace(re,"$1");
    alert(aNew);
  }
</script>
<
script type="text/javascript">   //3. 他就比較聰明了.....   var num=22.127456;   alert( Math.round(num*100)/100); </script>

<script type="text/javascript">   //4.會用新鮮東西的朋友....... 但是需要 IE5.5 才支持。   var num=22.127456;   alert( num.toFixed(2)); </script>

 



toFixed 方法

返回一個字符串,代表一個以定點表示法表示的數字。

numObj.toFixed([fractionDigits])

參數

numObj

必選項。一個 Number 對象。

fractionDigits

可選項。小數點后的數字位數。其值必須在 0 – 20 之間,包括 0 和 20。

說明

toFixed 方法返回一個以定點表示法表示的數字的字符串形式。該字符串中小數點之前有一位有效數字,而且其后必須包含 fractionDigits 數字。

如果沒有 fractionDigits 參數,或者該參數為 undefinedtoFixed 方法假定該值為 0。

 在寫腳本處理數字的時候肯定會經常用到toFixed方法。

     一、toFixed能做什么?

以下是摘自網絡的toFixed的介紹:

toFixed 方法:

返回一個字符串,代表一個以定點表示法表示的數字。

numObj.toFixed([fractionDigits])

參數

numObj

必選項。一個 Number 對象。

fractionDigits

可選項。小數點后的數字位數。其值必須在 0 – 20 之間,包括 0 和 20。

說明

toFixed 方法返回一個以定點表示法表示的數字的字符串形式。該字符串中小數點之前有一位有效數字,而且其后必須包含 fractionDigits 數字。

如果沒有 fractionDigits 參數,或者該參數為 undefinedtoFixed 方法假定該值為 0。

二、toFixed可以四舍五入嗎?

     答案是可以。但是問題也正在於此。這種四舍五入是不穩定的(不同的瀏覽器不一樣)。

     (1).

     在ie7下點擊按鈕會顯示0.00,而ff會是0.01。

    (2) 

     ie和ff都正常。

     可見對於ie而言有一部分數字在使用toFixed時是不能得到正確的四舍五入的結果的。這個問題可能很多朋友都沒有意識到,而這個問題說小也小,但有時候卻也會帶來惡劣的后果。

     就像上面0.009.toFixed(2)這個例子(0.009是一系列處理后的結果),恰好我就遇上了。在一個頁面當中因為是在后台代碼中做的計算因此顯示為1%,而在另一個頁面因為使用了toFixed結果顯示為0%。為此被客戶批了一頓。

     OK,既然有這樣的問題,又怎么解決呢?

三、替代方案:

     正如很多朋友所想,我們可以重寫這個方法:

     Number.prototype.toFixed = function( fractionDigits )...

     下面給出一個簡陋的解決方案:


Number.prototype.toFixed = function( fractionDigits )
{
    
//沒有對fractionDigits做任何處理,假設它是合法輸入
    return (parseInt(this * Math.pow( 10, fractionDigits  ) + 0.5)/Math.pow(10,fractionDigts)).toString();
}

覆寫toFixed后的顯示例子如下:


<html>
<head>
<script type="text/javascript">
Number.prototype.toFixed 
= function(s)
{
    
return (parseInt(this * Math.pow( 10, s ) + 0.5)/ Math.pow( 10, s )).toString();
}
</script>
</head>
<body>
<input onclick="alert(0.009.toFixed(2))" type="button" value="顯示0.009.toFixed(2)"> 
</body>
</html>

with 語句

為語句設定默認對象。

with (object)
   statements

參數

object

新的默認對象。

statements

一個或多個語句,object 是該語句的默認對象。

說明

with 語句通常用來縮短特定情形下必須寫的代碼量。在下面的例子中,請注意 Math 的重復使用:

x = Math.cos(3 * Math.PI) + Math.sin(Math.LN10) 
y = Math.tan(14 * Math.E)

當使用 with 語句時,代碼變得更短且更易讀:

with (Math){
   x = cos(3 * PI) + sin (LN10)  
   y = tan(14 * E)
}


免責聲明!

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



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