Open ntscshen opened 5 years ago
结论:由于浮点数运算的精度问题导致的。 为什么1:在计算机运算过程中,浮点数会通过 IEEE 754 标准进行转换,由于标准本身尾数位数有限制,需要将后面多余的尾数为截掉,所以在进制转换的时候精度已经损失了 为什么2:let x = 0.1 能得到真正的 0.1,标准中规定尾数的最大长度是53位,它最大可表示的是 2^53次方(9007199254740992)长度是16位, 0.1.toPrecision(16) -> "0.1000000000000000" 0.1.toPrecision(20) -> "0.100000000000000005551115123126" 这么看的话,在赋值时的 0.1 其实并不是真正意义上的 0.1,是意义上的 0.1 尾数的前16位。 结论就这样,那么如何去比较这道题呐?可以使用 JavaScript 提供的最小精度值,Number.EPSILON console.log(Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON); 检查等式左右两边差的绝对值是否小于 JS 中的最小精度,才是正确比较浮点树的方法。
结论:由于浮点数运算的精度问题导致的。
为什么1:在计算机运算过程中,浮点数会通过 IEEE 754 标准进行转换,由于标准本身尾数位数有限制,需要将后面多余的尾数为截掉,所以在进制转换的时候精度已经损失了
IEEE 754
为什么2:let x = 0.1 能得到真正的 0.1,标准中规定尾数的最大长度是53位,它最大可表示的是 2^53次方(9007199254740992)长度是16位, 0.1.toPrecision(16) -> "0.1000000000000000" 0.1.toPrecision(20) -> "0.100000000000000005551115123126" 这么看的话,在赋值时的 0.1 其实并不是真正意义上的 0.1,是意义上的 0.1 尾数的前16位。
let x = 0.1
0.1
0.1.toPrecision(16)
"0.1000000000000000"
0.1.toPrecision(20)
"0.100000000000000005551115123126"
结论就这样,那么如何去比较这道题呐?可以使用 JavaScript 提供的最小精度值,Number.EPSILON console.log(Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON); 检查等式左右两边差的绝对值是否小于 JS 中的最小精度,才是正确比较浮点树的方法。
JavaScript
Number.EPSILON
console.log(Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
JS
// 相加时简单的情况下,一个函数即可解决 function add(num1, num2) { const num1Digits = (num1.toString().split('.')[1] || '').length; const num2Digits = (num2.toString().split('.')[1] || '').length; const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits)); return (num1 * baseNum + num2 * baseNum) / baseNum; }
参考: 05 | JavaScript类型:关于类型,有哪些你不知道的细节? https://juejin.im/post/5b90e00e6fb9a05cf9080dff
实际开发中如何解决精度问题
可以使用第三方类库:Math.js
参考: 05 | JavaScript类型:关于类型,有哪些你不知道的细节? https://juejin.im/post/5b90e00e6fb9a05cf9080dff