【问题标题】:Python Infinity - Any caveats?Python Infinity - 有什么注意事项吗?
【发布时间】:2009-10-27 00:12:06
【问题描述】:

所以Python有正无穷和负无穷:

float("inf"), float("-inf")

这似乎是需要注意的功能类型。有什么我应该注意的吗?

【问题讨论】:

  • 请注意,常量1e309 将被解释为+inf-1e309 将被解释为-inf

标签: python infinity


【解决方案1】:

Python's implementation 很好地遵循了IEEE-754 standard,您可以将其用作指导,但它依赖于编译它的底层系统,因此可能会出现platform differences。最近¹,已经应用了一个允许"infinity" as well as "inf" 的修复程序,但这在这里并不重要。

以下部分同样适用于正确实现 IEEE 浮点运算的任何语言,它不仅仅针对 Python。

不平等比较

在处理无穷大和大于> 或小于< 运算符时,以下几点很重要:

  • 包括+inf在内的任何数字都高于-inf
  • 包括-inf在内的任何数字都小于+inf
  • +infneither higher nor lower 而不是 +inf
  • -inf 既不高于也不低于 -inf
  • 任何涉及NaN 的比较都是错误的(inf 既不高于也不低于NaN

平等比较

比较相等时,+inf+inf 相等,-inf-inf 也相等。这是一个备受争议的问题,对您来说可能听起来有争议,但它在 IEEE 标准中,Python 的行为就是这样。

当然,+inf 不等于 -inf,包括 NaN 本身在内的所有内容都不等于 NaN

无穷大计算

大多数具有无穷大的计算都会产生无穷大,除非两个操作数都是无穷大,当运算除法或模运算,或与零相乘时,需要牢记一些特殊规则:

  • 当乘以零时,结果未定义,它产生NaN

  • 将任何数字(除了无穷大本身)除以无穷大时,得到0.0-0.0²。

  • 当正或负无穷除以正或负无穷(包括模)时,结果是不确定的,所以NaN

  • 减法时,结果可能会出人意料,但请关注common math sense

  • 在做inf - inf时,结果未定义:NaN;

  • 在做inf - -inf时,结果是inf

  • 在做-inf - inf的时候,结果是-inf

  • 在做-inf - -inf时,结果未定义:NaN

  • 添加时,同样令人惊讶:

  • inf + inf时,结果是inf

  • inf + -inf时,结果未定义:NaN;

  • 在做-inf + inf时,结果未定义:NaN;

  • 在做-inf + -inf时,结果是-inf

  • 使用math.powpow** 很棘手,因为它的行为不符合应有的要求。当两个实数的结果太高而无法容纳双精度浮点数(它应该返回无穷大)时,它会引发溢出异常,但是当输入为inf-inf 时,它会正常运行并返回inf0.0。当第二个参数是NaN 时,它返回NaN,除非第一个参数是1.0。还有更多问题,不是全部covered in the docs

  • math.exp 遇到与math.pow 相同的问题。解决此溢出问题的一种解决方案是使用与此类似的代码:

      try:
          res = math.exp(420000)
      except OverflowError:
          res = float('inf')
    

注意事项

注意 1: 作为额外的警告,根据 IEEE 标准的定义,如果您的计算结果不足或溢出,结果将不会是不足或溢出错误,而是正或负无穷大:1e308 * 10.0 产生 inf

注意 2: 因为任何使用NaN 的计算都会返回NaN 并且任何与NaN 的比较,包括NaN 本身就是false,你应该使用math.isnan 函数确定一个数字是否确实是NaN

注 3: 虽然 Python 支持写入 float('-NaN'),但符号被忽略,因为 NaN 内部不存在符号。如果除以-inf / +inf,结果是NaN,而不是-NaN(没有这种东西)。

注意 4: 请小心依赖上述任何内容,因为 Python 依赖于为其编译的 C 或 Java 库,并非所有底层系统都正确实现了所有这些行为。如果您想确定,请在进行计算之前测试无穷大。


¹) 最近是指自从version 3.2.
²) 浮点数支持正负零,因此:x / float('inf') 保持其符号,-1 / float('inf') 产生 -0.01 / float(-inf) 产生 -0.01 / float('inf') 产生 0.0-1/ float(-inf) 产生 0.0 .另外,0.0 == -0.0 is true,如果你不希望它是真的,你必须手动检查标志。

【讨论】:

  • 一个小问题:并非每个无穷大的计算都会产生无穷大:-1 * float('infinity') == -inf
  • 这就是为什么我说它是一个small nitpick。你让我担心在使用无穷大时符号会被完全忽略,我想为其他人澄清一下。
  • 好吧,差不多:1 / float('infinity') == 0.0
  • @Phil:虽然我很确定您只是想证明并非所有使用 inf 的计算都会导致 inf 或 NaN,但我只是想让其他可能正在阅读 cmets 的人清楚,即 1/float('infinity')==0.0 为真;因为,当你接近无穷大时,除法的结果接近 0。我知道这只是基本的微积分,但我想确保那些阅读的人理解,或者至少知道为什么,结果就是它。
  • 我感觉这个答案比公认的答案好很多。
【解决方案2】:

您仍然可以通过涉及inf 的简单算术获得非数字 (NaN) 值:

>>> 0 * float("inf")
nan

请注意,您通常不会通过通常的算术计算得到inf 值:

>>> 2.0**2
4.0
>>> _**2
16.0
>>> _**2
256.0
>>> _**2
65536.0
>>> _**2
4294967296.0
>>> _**2
1.8446744073709552e+19
>>> _**2
3.4028236692093846e+38
>>> _**2
1.157920892373162e+77
>>> _**2
1.3407807929942597e+154
>>> _**2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
OverflowError: (34, 'Numerical result out of range')

inf 值被认为是一个非常特殊的值,具有不寻常的语义,因此最好通过异常立即了解 OverflowError,而不是将 inf 值静默注入到您的计算中。

【讨论】:

  • 一个简单的浮点加法、乘法等会很高兴地产生 inf:f=1.3407807929942597e+154; f*f => inf。引发 OverflowError 似乎是 ** 的一个例外。
  • @eregon,实际上,** 似乎有点小问题。当它溢出实数时,它会抛出一个错误,但当它的任何操作数是inf-inf 时,它会返回0.0inf。所以它确实在输入为无穷大时正常工作,但在结果应该为无穷大时却不能正常工作。
  • @Abel 这不是错误的。溢出意味着数量非常大。太大而无法表示它,但仍然小于无穷大。将无穷大放在这样的地方可能对您的特定应用程序逻辑的异常处理程序很有用,但对于 Python 来说通常是不正确的。
  • @Lutz 如果它作为乘法出现,那么它仍然是不一致的行为。当然 big*big 也不是无穷大。
【解决方案3】:

C99 也是如此。

所有现代处理器使用的 IEEE 754 浮点表示具有几个特殊的位模式,为正无穷(sign=0、exp=~0、frac=0)、负无穷(sign=1、exp=~0、 frac=0) 和许多 NaN(非数字:exp=~0, frac≠0)。

您只需要担心:一些算术可能会导致浮点异常/陷阱,但不仅限于这些“有趣”的常量。

【讨论】:

  • 所以如果我的算术太大可能会变成 inf?
  • @Casebash 不,它会导致OverflowError
【解决方案4】:

我发现了一个迄今为止没有人提到的警告。不知道实际情况会不会经常出现,这里是为了完整起见。

通常,计算模无穷大的数字会将自身返回为浮点数,但模无穷大的分数返回nan(不是数字)。这是一个例子:

>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan

我在 Python 错误跟踪器上提交了一个问题。可以在https://bugs.python.org/issue32968看到。

更新:这将是fixed in Python 3.8

【讨论】:

    【解决方案5】:

    一个非常糟糕的警告:除以零

    1/x 分数中,直到x = 1e-323 它是inf 但当x = 1e-324 或很少它抛出ZeroDivisionError

    >>> 1/1e-323
    inf
    
    >>> 1/1e-324
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: float division by zero
    

    所以要小心!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多