为什么Ruby的Float#round行为与Python不同?
“
Behavior of “round” function in Python”观察到,Python循环像这样漂浮:
>>> round(0.45,1) 0.5 >>> round(1.45,1) 1.4 >>> round(2.45,1) 2.5 >>> round(3.45,1) 3.5 >>> round(4.45,1) 4.5 >>> round(5.45,1) 5.5 >>> round(6.45,1) 6.5 >>> round(7.45,1) 7.5 >>> round(8.45,1) 8.4 >>> round(9.45,1) 9.4 接受的答案证实这是由于浮动体的二进制表示是不准确的,这是全部逻辑的. 假设Ruby浮动与Python的不一样,Ruby如何像人类一样漂浮? Ruby欺骗吗 1.9.3p194 :009 > 0.upto(9) do |n| 1.9.3p194 :010 > puts (n+0.45).round(1) 1.9.3p194 :011?> end 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 解决方法
概要
这两个实现都是面对同样的issues surrounding binary floating point numbers. Ruby通过简单的操作直接对浮点数进行操作(乘以10的幂,调整和截断). Python使用David Gay的复杂算法将二进制浮点数转换为字符串,该算法产生与二进制浮点数完全相等的最小十进制表示.这不会做任何额外的四舍五入,它是一个字符串的精确转换. 使用最短的字符串表示形式,Python将使用精确的字符串操作循环到适当的小数位数.浮点数转换的目标是尝试“撤消”一些二进制浮点表示错误(即如果输入6.6,则在6.6进行循环,而不是6.5999999999999996). 此外,Ruby与一些版本的Python在四舍五入模式中是不同的:从零开始到半数之间. 详情 Ruby不欺骗.它以简单的旧的二进制浮点数开头,Python是相同的.因此,它受到一些同样的挑战(这样的3.35略高于3.35,4.35表示略低于4.35): >>> Decimal.from_float(3.35) Decimal('3.350000000000000088817841970012523233890533447265625') >>> Decimal.from_float(4.35) Decimal('4.3499999999999996447286321199499070644378662109375') 查看实现差异的最好方法是查看底层的源代码: 这是一个链接到Ruby源代码:https://github.com/ruby/ruby/blob/trunk/numeric.c#L1587 Python源码从这里开始:http://hg.python.org/cpython/file/37352a3ccd54/Python/bltinmodule.c 后者有一个广泛的评论,揭示了两个实现之间的差异:
简而言之,Python 2.7非常愿意准确地遵循round-away-from-zero规则. 在Python 3.3中,同样重要的是准确地遵循round-to-even规则. 以下是_Py_dg_dtoa功能的一些额外的细节. Python调用float到string函数,因为它实现了一个算法,可以在相同的替代方案中给出最短的字符串表示.例如,在Python 2.6中,数字1.1显示为1.1000000000000001,但在Python 2.7及更高版本中,它只是1.1. David Gay’s sophisticated dtoa.c algorithm给出了“人们期待的结果”,而不用准确. 该字符串转换算法倾向于弥补对二进制浮点数的round()的任何实现的一些问题的弥补(即4.35开始的4.35而不是4.3499999999999944448662109375). 这和舍入模式(二分之一偶数与零四分之一)是Python和Ruby round()函数之间的本质区别. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |