問題這樣的:
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 參數,或者該參數為 undefined,toFixed 方法假定該值為 0。
在寫腳本處理數字的時候肯定會經常用到toFixed方法。
一、toFixed能做什么?
以下是摘自網絡的toFixed的介紹:
toFixed 方法:
返回一個字符串,代表一個以定點表示法表示的數字。
numObj.toFixed([fractionDigits])
參數
numObj
必選項。一個 Number 對象。
fractionDigits
可選項。小數點后的數字位數。其值必須在 0 – 20 之間,包括 0 和 20。
說明
toFixed 方法返回一個以定點表示法表示的數字的字符串形式。該字符串中小數點之前有一位有效數字,而且其后必須包含 fractionDigits 數字。
如果沒有 fractionDigits 參數,或者該參數為 undefined,toFixed 方法假定該值為 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)
}