我们知道, js里面的计算有时候是有误差的,是因为JavaScript使用二进制表示浮点数,因此不能精确表示所有十进制数
比如0.1 + 0.2不等于0.3
0.14 * 100不等于14
我一般是用这个函数处理的
Math.signFigures = function(num, rank = 6) { if(!num) return(0); const sign = num / Math.abs(num); const number = num * sign; const temp = rank - 1 - Math.floor(Math.log10(number)); let ans; if (temp > 0) { ans = parseFloat(number.toFixed(temp)); } else if (temp < 0) { ans = Math.round(number / Math.pow(10, temp)) * temp; } else { ans = Math.round(number); } return (ans * sign); };
这个函数是从网上来的, 比如计算0.1 + 0.2, Math.sign(0.1 + 0.2)就很准确的等于0.3
我没明白这个函数的运行原理是啥, 看不懂
回答:
该函数的原理是将输入数字 num 分解为正负号和绝对值。然后计算绝对值的有效数字位数,并根据 rank 参数进行调整。最后,将计算出的数字与其原始符号相乘,以恢复其符号。
具体实现过程如下:
- 如果输入数字为 0,则直接返回 0。
- 通过除以绝对值来提取数字的符号。
- 将数字的符号去掉后,计算数字的绝对值的有效数字位数。
- 根据 rank 参数调整有效数字位数,使用 toFixed() 方法将数字四舍五入到指定的有效数字位数。
- 如果计算出的有效数字位数小于 0,则将数字除以 10 的幂来提高有效数字位数。然后使用 Math.round() 方法将数字四舍五入到最接近的整数。
- 最后,将计算出的数字与其原始符号相乘,并将其作为函数的返回值。
这个出现的原理就是 js 底层存储数据的方案是这样的。number 都是 双精度 64 位二进制格式 IEEE 754 。
所以规避方法就是不用小数,直接整数计算。
当然,你这个看上去是是个 tofixed
Math.signFigures = function(num, rank = 6) { if(!num) return(0); const sign = num / Math.abs(num); const number = num * sign; const temp = rank - 1 - Math.floor(Math.log10(number)); let ans; if (temp > 0) { ans = parseFloat(number.toFixed(temp)); } else if (temp < 0) { ans = Math.round(number / Math.pow(10, temp)) * temp; } else { ans = Math.round(number); } return (ans * sign); }; console.log(Math.signFigures(0.1 + 0.2), 0.1 + 0.2) console.log(Math.signFigures(0.30000000000000004), 0.30000000000000004) console.log(Math.signFigures(0.987654321), 0.987654321) console.log(Math.signFigures(0.14 * 100), 0.14 * 100)

看了一下 java 好像也这样
