当前位置: 首页 > 科技观察

JavaScript浮点数和算术精度调整总结

时间:2023-03-13 05:53:54 科技观察

JavaScript只有一种数字类型Number,Javascript中所有的数字都是用IEEE-754标准格式表示的。浮点数的精度问题并不是JavaScript特有的,因为一些小数在二进制中有无限个数字。十进制二进制0.10.0001100110011001…0.20.0011001100110011…0.30.0100110011001100…0.40.0110011001100110…0.50.10.60.1001100110011001…0.50.10.60.1001100110011001…所以程序只能准确表示某个范围'1.1.1.1,这是不可避免的精度损失:JavaScript中的1.09999999999999999,问题比较复杂,下面是Chrome中的一些测试数据:console.log(1.0-0.9==0.1)//falseconsole.log(1.0-0.8==0.2)//falseconsole.log(1.0-0.7==0.3)//falseconsole.log(1.0-0.6==0.4)//trueconsole.log(1.0-0.5==0.5)//trueconsole.log(1.0-0.4==0.6)//trueconsole.log(1.0-0.3==0.7)//trueconsole.log(1.0-0.2==0.8)//trueconsole.log(1.0-0.1==0.9)//true怎么来怎么来避免这样的1.0-0.9!=0.1非错误问题?以下是目前使用较多的一个解决方案。在判断浮点运算的结果之前,会降低计算结果的精度,因为降低精度的过程总会自动四舍五入:(1.0-0.9).toFixed(digits)//toFixed()精度参数digits必须在0到20之间0.2)//trueconsole.log(parseFloat((1.0-0.7).toFixed(10))===0.3)//trueconsole.log(parseFloat((11.0-11.8).toFixed(10))===-0.8)//true写成方法://pass使用isEqual工具方法判断值是否相等functionisEqual(number1,number2,digits){digits=digits==undefined?10:digits;//默认精度为10,preferobject-orientedstyleNumber.prototype.isEqual=function(number,digits){digits=digits==undefined?10:digits;//默认精度为10returnthis.toFixed(digits)===number.toFixed(digits);}console.log((1.0-0.7).isEqual(0.3));//true接下来再试试浮点数的运算,console.log(1.79+0.12)//1.9100000000000001console.log(2.01-0.12)//1.889999999999997console.log(1.01*1.3)//1.3130000000000002console.log(0.69/10)//0.0689999999999999解决方法://加法函数,用于获取准确的加法结果//解释:会出现错误javascript的加法结果,两个浮点数相加时会更加明显。此函数返回更准确的加法结果。//调用:accAdd(arg1,arg2)//返回值:arg1加上arg2函数的精确结果accAdd(arg1,arg2){varr1,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=数学.pow(10,Math.max(r1,r2))return(arg1*m+arg2*m)/m}//给Number类型增加add方法,调用更方便。Number.prototype.add=function(arg){returnaccAdd(arg,this);}//减法函数,用于获取准确的减法结果//说明:javascript的加法结果会有错误,两个floating-的加法点数会更明显。此函数返回更准确的减法结果。//调用:accSub(arg1,arg2)//返回值:arg1函数减去arg2的准确结果accSub(arg1,arg2){varr1,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));//lastmodifybydeeka//动态控制精度长度n=(r1>=r2)?r1:r2;return((arg1*m-arg2*m)/m).toFixed(n);}//除法函数,用于获取准确的除法结果//说明:javascript除法结果会有错误,当两个浮点数相除时会更加明显。此函数返回更准确的除法结果。//调用:accDiv(arg1,arg2)//返回值:arg1除以arg2的准确结果functionaccDiv(arg1,arg2){vart1=0,t2=0,r1,r2;try{t1=arg1.toString().split(".")[1].length}catch(e){}try{t2=arg2.toString().split(".")[1].length}catch(e){}with(数学){r1=Number(arg1.toString().replace(".",""))r2=Number(arg2.toString().replace(".",""))return(r1/r2)*pow(10,t2-t1);}}//给Number类型增加一个div方法,调用起来更方便。Number.prototype.div=function(arg){returnaccDiv(this,arg);}//乘法函数,用于获取准确的乘法结果//说明:JavaScript乘法结果会有错误,两个浮点数相乘会比较明显的。此函数返回更准确的乘法结果。//调用:accMul(arg1,arg2)//返回值:arg1乘以arg2的准确结果functionaccMul(arg1,arg2){varm=0,s1=arg1.toString(),s2=arg2.toString();尝试{m+=s1.split(".")[1].length}catch(e){}尝试{m+=s2.split(".")[1].length}catch(e){}returnNumber(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)}//给Number类型增加一个mul方法,即打电话更方便。Number.prototype.mul=function(arg){returnaccMul(arg,this);
//验证:console.log(accAdd(1.79,0.12));//1.91console.log(accSub(2.01,0.12)));//1.89console.log(accDiv(0.69,10));//0.069
console.log(accMul(1.01,1.3));//经过1.313变换,可以愉快的浮点数相加减法,乘法和除法就搞定了~