Python 3.3.2 round函数并非"四舍五入"

对于一些貌似很简单常见的函数,最好还是去读一下Python文档,否则当你被某个BUG折磨得死去活来时,还不知根源所在.尤其是Python这种不断更新的语言.(python 2.7 的round和3.3.2不一样)

  • 3.3.2官方文档对round的定义

round(number[ndigits])

Return the floating point value number rounded to ndigits digits after the decimal point. If ndigits is omitted, it defaults to zero. Delegates to number.__round__(ndigits).

For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power minus ndigitsif two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2). The return value is an integer if called with one argument, otherwise of the same type as number.

  • 举例查看:
>>> round(1.5)
2
>>> round(2.5)
2
>>> round(3.5)
4
>>> round(4.5)
4
>>> round(5.5)
6
>>> round(6.5)
6

 

分析定义中的关键语句:

values are rounded to the closest multiple of 10 to the power minus ndigits
  • 假设round(123.45, 1)=A,那么A在数轴上是离123.45最近的点(the closest),且A保留1位小数.
  • "10 to the power minus ndigits"意思是"10的负ndigits次方",即pow(10, -ndigits).
  • "multiple of n" 表示n的倍数.倍数只能是整数,这个是关键.(可参考维基百科:http://zh.wikipedia.org/wiki/%E5%9B%A0%E6%95%B8)

那么,例如round(123.45, 1)就表示数轴上离123.45最近的"0.1的X倍".

X=1时,"0.1的X倍"(即0.1)是离123.45最近的值吗?显然不是,因为当X=1000时,"0.1的X倍"是100,比0.1更靠近123.45.

按照这个原理进行推导,容易知道当X=1234或1235时,"0.1的X倍"最靠近123.45.那么该取哪个X作为最终结果呢?

if two multiples are equally close, rounding is done toward the even choice 

"toward the even choice"意思就是说取偶数.即"0.1的1234倍",即123.4.

然而,当你测试round(123.45, 1):

>>> round(123.45, 1)
123.5

为什么取偶数呢?是BUG吗?非也,官方文档继续解释:

Note

The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information

意思就是说计算机需要先将十进制123.45转换为二进制,这个过程会导致二进制的值比123.45略大(比如123.45000001之类的),那么自然就得到123.5这个值了.

这种情形非常普遍:

>>> round(0.05, 1) #should return 0.0
0.1
>>> round(0.15, 1) #should return 0.2
0.1
>>> round(0.25, 1)
0.2
>>> round(0.35, 1) #should return 0.4
0.3
>>> round(0.45, 1) #should return 0.4
0.5

 

 

posted @ 2013-11-19 01:04  LisPythoniC  阅读(10663)  评论(1编辑  收藏  举报