为什么Python中的round函数如此奇怪?

15

我的代码:

  #!/usr/bin/python
  # -*- coding: utf-8 -*-
  print (round(1.555, 1))  # It seems normal
  print (round(1.555, 2))  # Why it is not output 1.56?
  print (round(1.556, 2))  # It seems normal

输出:

  sam@sam:~/code/python$ ./t2.py
  1.6
  1.55
  1.56
  sam@sam:~/code/python$

round(1.555, 1) 的输出结果为 1.6

为什么 round(1.555, 2) 的输出结果不是 1.56 呢?


请点击此处查看:https://dev59.com/q3VD5IYBdhLWcg3wL4mM - Robin Manoli
在任何编程语言中的浮点运算中,你永远不想依赖于一个数字确切地是什么的假设。因为同样的原因,你也不应该问if x == 2.0。这是关于浮点运算最重要的事情。 - cxrodgers
4个回答

18

请查看文档:

注意 对浮点数使用round()函数会得到令人惊讶的结果,例如round(2.675, 2)的结果是2.67而不是期望中的2.68。这不是一个错误:这是由于大多数十进制小数无法精确地表示为浮点数导致的。有关更多信息,请参见浮点算术问题与限制

如果您继续阅读(即单击该链接),您将找到一个与您类似的示例:

内置的round()函数的文档说明它会四舍五入到最接近的值,四舍五入时远离零。由于小数部分2.675恰好处于2.672.68之间,您可能希望在此处的结果是(二进制近似值)2.68。但实际上不是这样,因为当小数字符串2.675被转换为二进制浮点数时,它又被替换为一个二进制的近似值,其精确值是

2.67499999999999982236431605997495353221893310546875
字符串格式化也无法解决你的问题。浮点数的存储方式并不是你所期望的:
>>> '{:0.2f}'.format(1.555)
'1.55'

这并不是真正的“修复”,但Python确实有一个decimal模块,它专门用于浮点算术:

>>> from decimal import Decimal
>>> n = Decimal('1.555')
>>> round(n, 2)
Decimal('1.56')

6
直接引用文档:
浮点数的round()函数行为可能会让人感到惊讶:例如,round(2.675, 2)的结果是2.67而不是预期的2.68。这不是一个错误:这是由于大多数十进制小数不能精确表示为浮点数的结果。有关更多信息,请参见《Python浮点运算:问题与限制》。

1
换句话说,当你写 1.555 时,Python 实际上可能看到的是类似于 1.554999999999999999999999 的东西,因此四舍五入可能会变得奇怪。 - RodericDay

0

使用ROUND_CEILING函数进行小数取整:

>>> from decimal import Decimal, ROUND_CEILING, ROUND_FLOOR
>>> Decimal(1.555).quantize(Decimal('0.01'), rounding=ROUND_CEILING)
> Decimal('1.56')
>>> Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_CEILING)
> Decimal('2.68')
>>> Decimal(2.665).quantize(Decimal('0.01'), rounding=ROUND_FLOOR)
> Decimal('2.66')

0

来自 http://docs.python.org/2/library/functions.html#round

注意

对于浮点数,round()的行为可能会令人惊讶:例如,round(2.675, 2)给出的结果是2.67,而不是预期的2.68。这不是一个错误:它是由于大多数小数无法被完全表示成浮点数的事实所导致的。更多信息请参见浮点数算术:问题和限制。


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