Python 在元组内浮动,在访问时更改值

Python 在元组内浮动,在访问时更改值,python,Python,我有一个元组列表,每个元组有两个浮点数。每个元组代表一个范围。我正在浏览另一个浮动列表,这些浮动表示要适应范围的值。所有这些浮点数均小于1,但为正值,因此精度很重要。我的一个测试是确定某个值是否适合某个范围,但当它应该通过时,该测试失败了。如果我打印导致问题的值和范围,我可以告诉您: curValue = 0.00145000000671 range = (0.0014500000067055225, 0.0020968749796738849) 失败的条件是: if curValue &g

我有一个元组列表,每个元组有两个浮点数。每个元组代表一个范围。我正在浏览另一个浮动列表,这些浮动表示要适应范围的值。所有这些浮点数均小于1,但为正值,因此精度很重要。我的一个测试是确定某个值是否适合某个范围,但当它应该通过时,该测试失败了。如果我打印导致问题的值和范围,我可以告诉您:

curValue = 0.00145000000671 
range = (0.0014500000067055225, 0.0020968749796738849)
失败的条件是:

if curValue > range[0] and ... blah :
    # do some stuff
从CurveValue和range给出的值来看,测试应该明确通过(不要担心条件中的内容)。现在,如果我显式打印范围[0]的值,我会得到:

 range[0] =  0.00145000000671

这可以解释为什么测试失败了。那么我的问题是,为什么当访问浮点时,它会发生变化。当它是元组的一部分时,它具有高达某个精度的十进制值,当访问时,它具有不同的精度。为什么会这样?如何确保我的数据在计算过程中保持一致的精度?

在现代电脑中,浮动并没有那么精确。所以,即使你把π作为一个常数输入到100位小数,也只能得到其中一些精确值。同样的事情也发生在你身上。这是因为在32位浮点运算中,您只能得到24位尾数,这限制了您的精度(因为它是在base2中,所以以意想不到的方式)

请注意,
0.00145000000671
不是Python存储的精确值。如果使用
print
,Python只会显示完整存储的浮点数的小数。如果您想确切了解python如何存储浮点值,请使用
repr

如果您想要更高的精度,请使用该模块。

它本身不会改变。Python正在尽最大努力将数据存储为float,但是这个数字对于float来说太精确了,所以Python甚至在访问它之前(在存储它的过程中)就对它进行了修改。有趣的是,这么小的东西竟是这么大的痛苦


您需要使用任意固定点模块,如或模块。

浮动不会改变。内置的数字类型都是不可变的。你观察到的原因是:

  • print range[0]
    在浮点上使用
    str
    ,它(直到最新版本的Python)打印的浮点数字更少
  • 打印元组(无论是使用
    repr
    还是
    str
    )在单个项上使用
    repr
    ,这提供了更精确的表示(同样,在最近使用更好算法的版本中,这不再适用)

  • 至于为什么这个条件不能按你期望的方式工作,很可能是常见的罪魁祸首,浮动的有限精度。请尝试
    print repr(curVal),repr(range[0])
    以查看Python决定的是否是最接近您的浮点文字的表示形式。

    不确定它在这种情况下是否有效,因为我不知道Python是限制了输出还是限制了存储本身,但您可以尝试:

    if curValue - range[0] > 0 and...
    

    您确定
    0.00145000000671
    0.0014500000067055225
    可以准确地表示您所期望的内容吗?@Graham您能提供一个显示问题的5行示例程序吗?如果不是,问题可能出在代码中;)CurveValue>range[0]在我的机器上返回True…我们不应该担心的条件看起来像是你的问题…或者它实际上在做“事情”,而你只是没有意识到it@Graham:显示的值不一定是存储的值。请注意,小数仍然是浮点数,并且仍然具有有限的精度(尽管在默认情况下,小数的精度要大得多,并且可以调整),这与我们以前使用的以10为基数而不是以2为基数的精度是一样的。Python的浮点是C的双精度,所以它不是32位浮点,但关于有限精度的注释仍然适用。@delnan,python十进制模块不会有这样的不精确性,它不是关于base@Anurag:是的,它们只是与基本2浮动的不同。尝试
    Decimal(1)/Decimal(3)
    例如-结果不能用以10为底的有限位数的位置表示法表示。@delnan,这不是点结果,可能不表示1/3,但无论它表示什么都是精确的,即十进制('0.3333333'))你可以为你的用例改变精度,这与floats不同。这是帮助我发现问题的答案。事实证明,curValue和range[0]实际上是相等的,尽管我认为curValue更大。