当我对浮点数进行数学运算时,我永远无法准确理解 JavaScript 到底发生了什么。我一直非常害怕使用小数,以至于我尽可能避免使用它们。然而,如果我知道 IEEE 754 标准的幕后发生了什么,那么我就能够预测会发生什么;有了可预测性,我就会更加自信,不再那么恐惧。
有人可以给我一个简单的解释吗(就像解释整数的二进制表示一样简单关于 IEEE 754 标准如何工作以及它如何产生这种副作用:0.1 + 0.2 != 0.3
?
非常感谢! :)
像 0.1 这样的小数分数不能用 2 为基数清晰地表达
假设我们想以 2 为基数表示小数 0.1。我们知道它等于1/10。以 2 为底数的 1 除以 10 的结果是0.000110011001100...
具有重复的小数序列。
因此,虽然在十进制形式中,实际上很容易清晰地表示像 0.1 这样的数字,但在以 2 为基数的情况下,您无法精确地表示基于 10 的有理数。您只能使用能够存储的尽可能多的位来近似它。
为简化起见,假设我们只有足够的存储空间来重现该数字的前 8 个有效二进制数字。存储的数字为 11001100(以及 11 的指数)。这会转换回以 2 为基数的 0.000110011,十进制表示为 0.099609375,而不是 0.1。这是如果将 0.1 转换为以 8 位存储基值(不包括符号位)的理论浮点变量时会发生的错误量。
浮点变量如何存储值
IEEE 754 标准指定了一种用符号和二进制指数对实数进行二进制编码的方法。指数应用在binary域,这意味着在转换为二进制之前不要移动小数点,而是在转换之后进行。
IEEE 浮点数有不同的大小,每一种都指定有多少个二进制数字用于基数以及多少个二进制数字用于指数。
当你看到0.1 + 0.2 != 0.3
,这是因为您实际上并不是在 0.1 或 0.2 上执行计算,而是仅在浮点二进制中对这些数字的近似值执行一定精度的计算。由于此错误,将结果转换回十进制后,结果将不完全是 0.3。此外,结果甚至不等于二进制近似值 0.3。实际误差量将取决于浮点值的大小,以及使用的精度位数。
舍入有时有帮助,但在这种情况下没有帮助
在某些情况下,由于转换为二进制时的精度损失而导致的计算错误足够小,可以在再次从二进制转换回值时对值进行四舍五入,因此您永远不会注意到任何差异 - 它看起来像这样工作了。
IEEE 浮点对于如何进行舍入有特定的规则。
然而,对于 0.1 + 0.2 与 0.3,舍入并不能消除误差。0.1 和 0.2 的二进制近似值相加的结果将与 0.3 的二进制近似值不同。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)