为什么将浮点数1.4999999999999999四舍五入为2?

4
我一直在阅读一本书《编写高质量代码:深入计算机理解内部原理》。在关于四舍五入的章节中,它说:

如果小数位的值大于或等于可以表示的总小数值的一半,则应将数字舍入到最小的更大数字。

这意味着:
round(1.5) // equals 2
round(1.49) // equals 1

但是当我用Python尝试这个操作时:
x1 = 1.4999  # rounds to 1

x2 = 1.4999999999999999  # rounds to 2

print(round(x1))

print(round(x2))

输出结果如下:

1

2

我尝试使用C#和Swift进行相同的操作,结果也一样。因此我认为这是一个与语言无关的主题。
但是为什么会出现这种情况呢?
我的假设是,浮点数单元在应用程序员的舍入之前,将额外的位四舍五入,将"1.4999999999999999999"转换为"1.5"。

5
抱歉,跳错了。1.4999999999999999999 这个数不是浮点数能够单独表示的数字,与 1.5 相区分。浮点数是实数的近似值。 - Martijn Pieters
3
在二进制中无法准确表示它,最接近的浮点数表示恰好是 1.51.4999999999999999 == 1.5True。如果去掉一个 9,你会看到你期望的行为:略小于 1.5 的数字确实被舍入为向下取整。 - John Kugelman
4
假设使用IEEE 754 64位二进制表示,将实数1.4999999999999999999四舍五入为1.5的误差为1E-19。将其向下舍入到下一个可精确表示的较小数字1.4999999999999997779553950749686919152736663818359375的误差为2.219446049250313080847263336181640625E-16。这是在转换为浮点数时进行的简单“四舍五入至最近”的情况。 - Patricia Shanahan
1个回答

8

在代码 x2 = 1.4999999999999999print(round(x2)) 中,有两个操作会影响这个值。round 函数不能直接对数字 1.4999999999999999 或数字 "1.4999999999999999" 进行操作。它的操作数必须是 Python 实现使用的浮点格式。

于是首先将 1.4999999999999999 转换成浮点格式。Python 并没有严格规定 Python 实现使用哪种浮点格式,但 IEEE-754 基本 64 位二进制格式是常见的。在这种格式中,距离 1.4999999999999999 最接近的可表示值是 1.5 和 1.4999999999999997779553950749686919152736663818359375。前者比后者更接近 1.4999999999999999,因此选择前者。

因此,将 1.4999999999999999 转换为浮点格式得到 1.5。然后round(1.5) 得到 2。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接