了解如何修复 JavaScript 中的小数运算问题
如果你在 JavaScript 中尝试对两个小数进行求和,你可能会有一个惊喜。
0.1 + 0.1
是,如你所预期的,0.2
但是有时候你会得到一些意外的结果。
比如 0.1 + 0.2
。
结果并不是如你预期的 0.3
,而是 0.30000000000000004
。
或者 1.4 - 1
,结果是 0.3999999999999999
我确定你的问题是:为什么会这样?
首先,这不仅仅是 JavaScript 的问题,对于每一种编程语言都是一样的。
原因是计算机将数据存储为二进制的 0
或 1
。
任何一个值都可以表示为二进制数字系统中的一个 2 的幂。
1 可以表示为 1 * 2^0
10 可以表示为 1 * 2^1 + 0 * 2^0
并不是每个十进制数字都能够完美地在这个二进制格式中表示,因为一些数字在二进制中是重复的数字。尝试将 0.1 从十进制转换为二进制。
简而言之,我们需要无限精度来表示 0.1,虽然计算机可以很好地近似,但当我们进行计算时,我们会失去一些数据,因为我们需要在某个地方“截断”,这就导致了你在上面看到的那些意外的结果。
你可以使用像 decimal.js、bignumber.js 或 big.js 这样的库。
你也可以使用这样的“技巧”。
你决定在小数点后面截断两个位置,例如,将数字乘以 100 来去除小数部分。
然后在求和后除以 100:
0.1 + 0.2 //0.30000000000000004
(0.1.toFixed(2) * 100 + 0.2.toFixed(2) * 100) / 100 //0.3
使用 10000
而不是 100
来保留 4 位小数。
更抽象化的方式:
const sum = (a, b, positions) => {
const factor = Math.pow(10, positions)
return (a.toFixed(positions) * factor + b.toFixed(positions) * factor) / factor
}
sum(0.1, 0.2, 4) //0.3