带浮点数的Python舍入错误

带浮点数的Python舍入错误,python,Python,我不知道这是否是一个明显的bug,但是当运行Python脚本来改变模拟的参数时,我意识到delta=0.29和delta=0.58的结果丢失了。在调查中,我注意到以下Python代码: for i_delta in range(0, 101, 1): delta = float(i_delta) / 100 (...) filename = 'foo' + str(int(delta * 100)) + '.dat' 为delta=0.28和0.29生成了相同的文件,与.57和.5

我不知道这是否是一个明显的bug,但是当运行Python脚本来改变模拟的参数时,我意识到delta=0.29和delta=0.58的结果丢失了。在调查中,我注意到以下Python代码:

for i_delta in range(0, 101, 1):
  delta = float(i_delta) / 100

  (...)

filename = 'foo' + str(int(delta * 100)) + '.dat'
为delta=0.28和0.29生成了相同的文件,与.57和.58相同,原因是python将float(29)/100返回为0.2899999998。但这并不是一个系统性错误,也不是每个整数都会发生这种错误。因此,我创建了以下Python脚本:

import sys

n = int(sys.argv[1])

for i in range(0, n + 1):
  a = int(100 * (float(i) / 100))
  if i != a: print i, a

我看不出在数字中有任何模式会出现这种舍入错误。为什么这些特殊的数字会发生这种情况?

任何不能由2的精确幂构成的数字都不能精确地表示为浮点数;需要对其进行近似计算。有时,最接近的近似值将小于实际值


阅读。

这是众所周知的,因为它的性质

如果你想做十进制算术而不是浮点算术,你可以这样做

例如:

一般来说,十进制可能太过分了,在少数情况下,当数字没有有限的十进制表示时,仍然会有舍入错误(例如分母不是1或可被2或5整除的任何分数-十进制基数的因子(10))。例如:

>>> s = Decimal(7)
>>> Decimal(1)/s/s/s/s/s/s/s*s*s*s*s*s*s*s
Decimal('0.9999999999999999999999999996')
>>> int(Decimal('0.9999999999999999999999999996'))
0
因此,最好在将浮点转换为整数之前始终四舍五入,除非您需要一个floor函数

>>> int(1.9999)
1
>>> int(round(1.999))
2

另一种选择是使用库中不近似的分数类。(它只是根据需要不断地对整数分子和分母进行加减和相乘)。

这就是IEEE 754浮点数字的工作原理。我建议您将浮点值转换回整数,而不是简单地截断。这不是一个错误——这在许多不同的语言中都很常见。有一些演练,但在这种情况下,最简单的解决方案可能只是在文件名中使用idelta。请记住,默认情况下,idelta不会传递到循环外部。#StdSOAnswer_1。浮点就是这样工作的。@Tadeck我想说这仍然是一个错误,它只是现代计算机科学中的一个特有现象。老实说,在发布同一个链接之前,我没有看到您指向同一文档的链接。这说明它是一个很好的参考资料。@jimbob,我在原始帖子一分钟后添加了这个链接。这是一本经典著作,但我并没有马上就拿到它。对于Pythonistas来说,这本书中还有一个更短(更容易阅读)的章节来讨论这个问题。嗯,实际上一个更好的例子是Decimal(1)/Decimal(3)*Decimal(3),它不能产生更精确的1.0。“当基数不是10”应该是当分数不能在基数10中精确表示时。“数字当然是以10为基数的。”德雷克利茨同意,我的回答是草率的。您的示例更简洁(尽管两者都同样有效)。当数字没有以10为基数的有限十进制表示形式时,应该写入,当分母不能被2或5整除时,任何分数都会发生这种情况。(就算“分数不能精确地以10为基数来表示。数字当然是以10为基数的。”也不完全正确。数字没有基数。三分之一=1/(1+1+1)完全不考虑基数。以分数的形式书写,它可以以10为基数来表示——1/3。)@jimbob博士我喜欢上面的改进,但是,我不喜欢“数字没有基础”的说法。也许区别在于语义,但词语的意义很重要。一个数字应该代表一个值(或者数量,如果你愿意的话)。为了创建一个编号系统,需要选择一个基数,需要选择符号,我们可以比简单的计数更有效地交流,但我相信这就是你的意思:)@DerekLitz-是的,数字代表值,但只有数字的表示才有基数。一,二,二十八,三个半,π是数字。十进制表示法分别为:1、2、28、1.5、3.14159。。。(十进制表示以10为基数)是的,数字名称通常与以10为基数有关。在二进制(基数2)中,它们是1,10,11100,1.1,11.0010 0100 0011 1111…,在十六进制中是:1,2,1c,1.8,3.243f。。。数字有一个特定的数学含义,指的是抽象对象(例如,数字2是零的第二个后继者:2=succ(succ zero)),不考虑基数。@dr_jimbob我喜欢这些对话:)。这更多的是“数字”定义的模糊性,它可以是表示数学值的抽象,也可以是表示数学值的抽象。当我熟悉数学类型时,这当然是一个好消息,我应该假设后者:)
>>> int(1.9999)
1
>>> int(round(1.999))
2