【问题标题】:Different behavior of float32/float64 numpy variablesfloat32/float64 numpy 变量的不同行为
【发布时间】:2013-08-19 09:45:40
【问题描述】:

在谷歌上搜索了一段时间后,我在这里发帖寻求帮助。

我有两个从函数返回的 float64 变量。 他们两个显然都是1:

>>> x, y = somefunc()
>>> print x,y
>>> if x < 1 :   print "x < 1"
>>> if y < 1 :   print "y < 1"
1.0  1.0
y < 1

当变量定义为 float32 时,行为会发生变化,在这种情况下,'y

我试过设置

np.set_printoptions(precision=10)

期望看到变量之间的差异,但即便如此,它们在打印时都显示为 1.0。

在这一点上我有点困惑。 有没有办法可视化这些 float64 数字的差异? 是否可以可靠地使用“if/then”来检查 float64 数字?

谢谢 特雷瓦雷斯

【问题讨论】:

  • 我不明白你的问题。显然,错误出现在打印表示中,其中y 小于float64 情况下的一,并且在使用float32 时由于舍入错误而等于(或大于)1。在处理浮点值时,您应该永远使用相等比较。修复一个最小错误(例如epsilon=1e-16 或更小/更大,具体取决于应用程序)并执行if abs(number - 1) &lt; epsilon: # number is sufficiently close to 1 to be considered as 1
  • @Bakuriu 您可以将此作为答案发布...您几乎解释了发生了什么

标签: python numpy


【解决方案1】:

打印的值不正确。在您的情况下,y 在使用float64 时小于1,在使用float32 时大于或等于1。这是意料之中的,因为舍入误差取决于float 的大小。

为避免此类问题,在处理浮点数时,您应该始终确定一个“最小误差”,通常称为epsilon,而不是比较是否相等,而是检查结果是否最远epsilon从目标值:

In [13]: epsilon = 1e-11

In [14]: number = np.float64(1) - 1e-16

In [15]: target = 1

In [16]: abs(number - target) < epsilon   # instead of number == target
Out[16]: True

特别是,numpy 已经提供了np.allclose,这对于在给定一定容差的情况下比较数组是否相等很有用。即使参数不是数组(例如np.allclose(1 - 1e-16, 1) -&gt; True),它也可以工作。

但请注意,numpy.set_printoptions 不会影响 np.float32/64 的打印方式。它只影响 arrays 的打印方式:

In [1]: import numpy as np

In [2]: np.float(1) - 1e-16
Out[2]: 0.9999999999999999

In [3]: np.array([1 - 1e-16])
Out[3]: array([ 1.])

In [4]: np.set_printoptions(precision=16)

In [5]: np.array([1 - 1e-16])
Out[5]: array([ 0.9999999999999999])

In [6]: np.float(1) - 1e-16
Out[6]: 0.9999999999999999

另请注意,在交互式解释器中执行 print y 或评估 y 会产生不同的结果:

In [1]: import numpy as np

In [2]: np.float(1) - 1e-16
Out[2]: 0.9999999999999999

In [3]: print(np.float64(1) - 1e-16)
1.0

不同之处在于print 调用str 而评估调用repr

In [9]: str(np.float64(1) - 1e-16)
Out[9]: '1.0'

In [10]: repr(np.float64(1) - 1e-16)
Out[10]: '0.99999999999999989'

【讨论】:

  • 谢谢 Bakuriu,这是一个相当全面的答案,澄清了我的疑惑。
  • 我只是想知道 Numpy 提供函数作为“numpy.where”的意义何在,而没有警告浮点数的这些微妙之处?从文档中可以看出,可以直接与浮点数一起使用而无需考虑精度问题: >>> x = np.arange(9.).reshape(3, 3) >>> x[np.where( x > 3.0 )] 数组([ 4., 5., 6., 7., 8.])
  • @Trevarez 不是 numpy 的问题。这是 any 浮点计算的问题。这是您应该知道的(例如参见What Every Computer Scientist Should Know About Floating-Point Arithmetic)。如果您想检查值在哪里大于3.0,达到一定精度,您可以简单地先减去 epsilon(即x[np.where((x - epsilon) &gt; 3.0)])。
  • 很棒的文章。我想我终于明白了“问题”的范围。再次感谢您的解释。
  • 注意:你应该使用np.allclose(value, other_value)。不要定义您自己的任意 epsilon 值。
【解决方案2】:
In [26]: x  = numpy.float64("1.000000000000001")

In [27]: print x, repr(x)
1.0 1.0000000000000011

换句话说,您受到print 语句中精度损失的困扰。该值与1 略有不同。

【讨论】:

  • 看,print 输出 11 个有效数字,而 float64 有 15 个左右。
【解决方案3】:

根据此处提供的建议,我以这种方式总结答案:

为了在浮点数之间进行比较,程序员必须定义一个最小距离 (eps) 以使它们被认为是不同的(例如,eps=1e-12)。这样做,条件应该写成这样:

Instead of (x>a), use (x-a)>eps
Instead of (x<a), use (a-x)>eps
Instead of (x==a), use abs(x-a)<eps

这不适用于整数之间的比较,因为它们之间的差固定为 1。

希望它能像帮助我一样帮助其他人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-16
    • 2016-06-14
    • 1970-01-01
    • 2016-05-15
    • 2018-02-07
    • 1970-01-01
    • 2019-11-03
    • 2019-07-28
    相关资源
    最近更新 更多