javascript解决小数的加减乘除精度丢失的方案

原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况.
(js)的小数点加减乘除问题 , 是一个js的bug如0.3*1 = 0.等 , 下面列出可以完美求出相应精度的四种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 accMul((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 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)); n=(r1>=r2)?r1:r2; return ((arg1*m-arg2*m)/m).toFixed(n); }
下面我们来具体分析洗在中关于数字精度的丢失问题
一、JS数字精度丢失的一些典型问题
1. 两个简单的浮点数相加
0.1 + 0.2 != 0.3 // true
这真不是的问题 , 可以用alert试试 (哈哈开玩笑) 。
看看Java的运算结果
再看看
2. 大整数运算
==// ?
16位和17位数竟然相等 , 没天理啊 。
又如
var x = 90992
x + 1 == x // ?
看结果
三观又被颠覆了 。
3. 不会四舍五入()
【javascript解决小数的加减乘除精度丢失的方案】1.335.(2) // 1.33
线上曾经发生过中价格和其它浏览器不一致 , 正是因为兼容性问题导致
二、JS 数字丢失精度的原因
计算机的二进制实现和位数限制有些数无法有限表示 。就像一些无理数不能有限表示 , 如 圆周率 3.... , 1.3333... 等 。JS 遵循IEEE 754规范 , 采用双精度存储( ) , 占用 64 bit 。如图
意义
1位用来表示符号位11位用来表示指数52位表示尾数
浮点数 , 比如
0.1 >> 0.0 1001…(1001无限循环)
0.2 >> 0.0 0011…(0011无限循环)
此时只能模仿十进制进行四舍五入了 , 但是二进制只有 0 和 1 两个 , 于是变为 0 舍 1 入 。这即是计算机中部分浮点数运算时出现误差 , 丢失精度的根本原因 。
大整数的精度丢失和浮点数本质上是一样的 , 尾数位最大是 52 位 , 因此 JS 中能精准表示的最大整数是 Math.pow(2, 53) , 十进制即 90992 。
大于 90992 的可能会丢失精度
90992 >> 000...000 // 共计 53 个 0
90992 + 1 >> 000...001 // 中间 52 个 0
90992 + 2 >> 000...010 // 中间 51 个 0
实际上
90992 + 1 // 丢失
90992 + 2 // 未丢失
90992 + 3 // 丢失
90992 + 4 // 未丢失
结果如图
以上 , 可以知道看似有穷的数字, 在计算机的二进制表示里却是无穷的 , 由于存储位数限制因此存在“舍去” , 精度丢失就发生了 。
想了解更深入的分析可以看这篇论文(又长又臭):What EveryKnow About -Point
三、解决方案
对于整数 , 前端出现问题的几率可能比较低 , 毕竟很少有业务需要需要用到超大整数 , 只要运算结果不超过 Math.pow(2, 53) 就不会丢失精度 。