前言
最近在做项目的时候,涉及到产品价格的计算,JS浮点数的准确性经常出现,这对于财务管理系统的开发者来说是一个非常严重的问题(所有和钱有关的问题都是严重的问题)。在这里,我将整理相关的原因和解决方法,希望能给大家提供一些参考。
一.常见例子
//加0.1 0.2=0.3000000000004 0.1 0.7=0.7999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
JavaScript中只有一个Number类型,也就是说JavaScript语言的底部没有整数,所有的数字都以IEEE-754标准格式存储为64位浮点数,1与1.0相同。因为有些小数是用二进制表示的,所以位数是无限的。JavaScript会丢弃超过53位的二进制文件,所以涉及小数的比较和操作要非常小心。
Iii .IEEE二进制浮点运算标准(IEEE 754)
IEEE二进制浮点运算标准(IEEE 754)是20世纪80年代以来应用最广泛的浮点运算标准,被许多中央处理器和浮点运算单元采用。本标准定义了表示浮点数(包括负零-0)和反规范数)、一些特殊值(infinity (Inf)和非数值(NaN))的格式,以及这些值的“浮点运算符”。它还指出了四个数字舍入规则和五个例外(包括例外的时间和处理)。
4.浮点数的存储
JS的浮点数实现也遵循IEEE 754标准,采用双精度,用64位定长表示,其中1位表示符号位,11位表示指数,52位表示尾数。下图:
符号位:第一位为正负符号位,0表示正数,1表示负指数位:中间11位存储指数,用于表示幂数的尾数:最后52位为尾数,超出部分自动四舍五入为1和5。浮点数的计算步骤(0.1 0.2)
[1]首先,十进制0.1和0.2将被转换为二进制,但是浮点数在二进制表示中是无限的
0.1——0.0001 1001 1001 .(1001周期)0.2——0.0011 0011 0011 0011.(0011周期)
【2】IEEE754标准中64位双精度浮点数的小数部分最多支持53位二进制,冗余的二进制数被截断,所以两者相加后的二进制和为
0.0100110011001100110011001100110011001100110011001101
[3]截断后的二进制数转换成十进制后,就变成了0.300000000000000000000000000000000000000000000000000000000000000000000000000
不及物动词解决方法
[1]参考类库
Math.jsdecimal.jsbig.js [2]思路一:在知道小数位数的前提下,可以考虑将浮点数放大成整数(最后除以相应的倍数)再进行运算,这样就可以得到正确的结果。
0.1 0.2 —— (0.1 * 10 0.2 * 10)/10 //0.30.8 * 3 —— (0.8 * 100 * 3)/100 //2.4
[3]自定义转换和处理功能
//f表示要计算的表达式,数字表示十进制数字数学。formatfloat=function (f,数字){//math。幂(指数,幂指数)var m=Math.pow(10,数字);//Math.round () round返回Math.round(f * m,10)/m;} console . log(Math . format float(0.3 * 8,1));//2.4 console . log(math . format float(0.35 * 8,2));//2.8 [4]加法功能
/* * * *加法函数,用于得到准确的加法结果* *说明:javascript的加法结果会有错误,两个浮点数相加会很明显。该函数返回更精确的加法结果。* *调用:accAdd(arg1,arg2) **返回值:arg1加arg2的精确结果* */函数accadd (arg1,arg2) {varr1,R2,m,c;尝试{ r1=arg1.toString()。拆分('.')[1].长度;} catch(e){ R1=0;}尝试{ r2=arg2.toString()。拆分('.')[1].长度;} catch(e){ R2=0;} c=Math . ABS(R1-R2);m=Math.pow(10,Math.max(r1,R2));if(c ^ 0){ var cm=math . pow(10,c);if(R1 R2){ arg 1=NumBer(arg 1 . ToString()。替换('.', ''));arg2=Number(arg2.toString()。替换('.',' '))* cm} else { arg 1=Number(arg 1 . tostring()。替换('.',' '))* cmarg2=Number(arg2.toString()。替换('.', ''));} } else { arg 1=Number(arg 1 . tostring()。替换('.', ''));arg2=Number(arg2.toString()。替换('.', ''));}返回(arg 1 arg 2)/m;}//在Number类型中增加一个add方法,调用起来更方便。number . prototype . add=function(arg){ return accAdd(arg,this);};[5]减法功能
/* * * *减法函数,用来得到精确的减法结果* *说明:javascript减法结果会有误差,两个浮点数相减会很明显。该函数返回更精确的减法结果。* *调用:accSub(arg1,arg2) **返回值:arg1加arg2的精确结果* */函数accsub (arg1,arg2) {varr1,R2,m,n;尝试{ r1=arg1.toString()。拆分('.')[1].长度;} catch(e){ R1=0;}尝试{ r2=arg2.toString()。拆分('.')[1].长度;} catch(e){ R2=0;} m=Math.pow(10,Math.max(r1,R2));//最后由deeka修改//动态控制精度长度n=(r1=r2)?r1 : r2返回((arg1 * m - arg2 * m)/m)。toFixed(n);}//在Number类型中加入mul方法,调用起来更方便。number . prototype . sub=function(arg){ return accMul(arg,this);};[6]乘法函数
/* * * *乘法函数,用来得到精确的乘法结果* *说明:javascript的乘法结果会有误差,两个浮点数相乘会很明显。该函数返回更精确的乘法结果。* *调用:accMul(arg1,arg2) **返回值:arg1乘以arg2的精确结果* */函数accmul (arg1,arg2) {var m=0,S1=arg1.tostring(),S2=arg 2 . tostring();尝试{ m=s1.split(' . ')[1].长度;} catch (e) {} try { m=s2.split(' . ')[1].长度;} catch(e){ } return Number(S1 . replace(' . ',' '))*编号(s2.replace(' . ',' '))/Math.pow(10,m);}//在Number类型中加入mul方法,调用起来更方便。number . prototype . mul=function(arg){ return accMul(arg,this);};[7]除法功能
/* * * *除法函数,用来得到精确的除法结果* *说明:javascript除法结果会有错误,两个浮点数相除时会很明显。该函数返回更精确的除法结果。* *调用:accDiv(arg1,arg2) **返回值:arg1除以arg2的精确结果* */函数accdiv (arg1,arg2) {vart1=0,T2=0,R1,R2;尝试{ t1=arg1.toString()。拆分('.')[1].长度;} catch (e) {}尝试{ t2=arg2.toString()。拆分('.')[1].长度;}用(Math) { r1=Number(arg1.toString)()捕获(e) {}。替换('.', ''));r2=Number(arg2.toString()。替换('.', ''));返回(r1/r2) *幂(10,T2-t1);} }//在Number类型中增加一个div方法,调用起来更方便。number . prototype . div=function(arg){ return accDiv(this,arg);};摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。