情境描述
最近在开发专案的前端时,遇到一件非常奇怪的问题,用Javascript来做加减乘除,如果是有小数点
的数字的话,跑出来的数字会非常奇特,例如:
var number1 = 5.10;var number2 = 100.00;$('#msg').html(number1 * number2);
显示出来的数字会是
509.99999999999994
原因
Google了一下js 除法 浮点数 问题
,发现主要问题在于Javascript是用二进制来计算数值,之后再转换成十进制,举个例子,0.1 + 0.2,在Javascript会是这样子计算的。
// 0.1 和 0.2 都转化成二进位制后再进行运算0.00011001100110011001100110011001100110011001100110011010 +0.0011001100110011001100110011001100110011001100110011010 =0.0100110011001100110011001100110011001100110011001100111// 转成十进位制正好是 0.30000000000000004
解决方法
外部套件
引用Math.js或者BigDecimal.js等,均可以顺利解决浮点数运算的问题。
自订四则运算程式码
若是觉得不想要额外引用套件时,可以自己写四则运算(+ - * /)的方法如下:
//除法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); } }//乘法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);}//加法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 accSubtr(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)); n=(r1>=r2)?r1:r2; return ((arg1*m-arg2*m)/m).toFixed(n);}
结语
虽然只是小问题,爬个文简单就可以解决,但其实就是这个问题,害我金额算出来都错误,被客户骂还不知道问题出在哪,一个一个下中断点才找到这个运算的Bug,所以小细节也会衍生出大问题,希望能帮助到跟我一样明明算式正确,数字却一直错误的伙伴们。
参考文章
JavaScript 浮点数陷阱及解法
js浮点数精度计算问题解决