可能的重复:
JavaScript 的数学被破坏了吗?
在 Javascript 中,我无法弄清楚为什么230/100*100
返回229.99999999999997
,而240/100*100
返回240.
这也适用于460, 920
等等......
有什么解决办法吗?
可能的重复:
JavaScript 的数学被破坏了吗?
在 Javascript 中,我无法弄清楚为什么230/100*100
返回229.99999999999997
,而240/100*100
返回240.
这也适用于460, 920
等等......
有什么解决办法吗?
230/100*100
= (230 / 100) * 100
= 2.3 * 100 in binary
二进制中的2.3是循环十进制:10.01001100110011001100110011001100...
由于精度有限,这个循环小数无法准确表示,我们得到类似2.29999999981373548507...
.
有趣的是,如果您选择这样的除法运算,使其可以用二进制准确表示(不是循环小数,所有数字都在 FP 标准所容纳的最大有效数字内),您将不会看到任何此类差异。
例如225/100*100
=225
2.25
二进制是10.01
检查浮点值之间的相等性时,请始终注意精度。向上/向下舍入到一定数量的有效数字是一种很好的做法。
在 JavaScript 中,所有数值都存储为IEEE 754 64 位浮点值(double
在许多语言中也称为)。这种表示只有有限的精度(因此并非所有数字都可以准确表示)并且它是二进制的,因此看起来很容易用十进制表示的值可能会变得难以处理。
没有适合所有人的即用即弃的解决方案。如果您需要一个整数,那么只需使用Math.round
.
此问题与浮点不准确性有关。有关更多详细信息,请参阅此问题: 浮点数学是否损坏?
出于同样的原因,如果你被迫保持一定的精度,并采取每一步,你会给出10/3*3
as 9.99999...
。
假设您必须保持的精度是 10 位数。在10/3
你有3.333333333
. 然后,当您将其乘以 3 时,您将拥有9.999999999
.
现在,既然我们知道 3 会永远持续下去,我们知道 9 会永远持续下去,所以我们知道答案真的是 10。但这不是这里的交易,交易是你尽可能地应用每一步可以,然后继续下一个。
除了会导致重复表示的数字外,可能还有一些可以精确表示的数字,但不能用您使用的位数表示。
正如10/3
十进制230/100
不能完美表示一样,二进制也不能完美表示。
JavaScript 中的除法不是整数除法,而是浮点数。
2.3 或 2.4 不能用浮点数精确表示。不同之处在于 2.4 最接近的 fp 是 2.4000000953,而 2.3 大约是 2.2999999523。
一个可以使用Math.round(x)
或一个可以使用 JavaScript 技巧:
(x|0) 将 x 转换为整数,如 '|' 运算符将操作数强制为整数。即使在这种情况下,299.9943 也不是四舍五入而是截断。