巨蟒无限-有什么要注意的吗?

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

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

这似乎是一个需要注意的特性类型。有什么我需要注意的吗?

156109 次浏览

C99也是。

所有现代处理器使用的 IEEE 754浮点表示都有一些特殊的位模式,这些位模式保留为正无穷大(sign = 0,exp = ~ 0,frac = 0)、负无穷大(sign = 1,exp = ~ 0,frac = 0)和许多 NaN (Not a Number: exp = ~ 0,frac ≠0)。

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

您仍然可以从涉及 inf的简单算术中得到非 a 数(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值静默地注入到计算中。

Python 的实现 很好地遵循了 IEEE-754标准,您可以将其用作指导,但是它依赖于编译它所依赖的底层系统,因此可能会出现 平台差异。最近,应用了一个允许 “无穷”和“ inf”的修复程序,但是这个修复程序在这里并不重要。

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

不平等的比较

当处理无穷大和大于或小于 <运算符时,计数如下:

  • 任何数字包括 +inf都高于 -inf
  • 任何数字包括 -inf都低于 +inf
  • +inf既不高也不低而不是 +inf
  • -inf既不高于也不低于 -inf
  • 任何涉及 NaN的比较都是错误的(inf既不高于 NaN,也不低于 NaN)

平等的比较

相等时,+inf+inf是相等的,-inf-inf也是相等的。这是一个备受争议的问题,您可能会觉得有争议,但它是在 IEEE 标准中的,Python 的行为就是这样。

当然,+inf不等于 -inf,任何东西,包括 NaN本身,都不等于 NaN

无穷大的计算

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

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

  • 当任何数字(除了无穷大本身)除以无穷大时,它产生 0.0-0.02。

  • 当把(包括模)正无穷大或负无穷大除以正无穷大或负无穷大时,结果是未定义的,因此 NaN

  • 在减法时,结果可能令人惊讶,但按照 数学常识:

  • 当做 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。还有更多的问题,不是所有的 pow0。

  • math.expmath.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 库,并非所有底层系统都正确地实现了所有这些行为。如果您想要确定,那么在进行计算之前测试无穷大。


1)最近指自 版本3.2以来。
2)浮点数支持正负零,因此: x / float('inf')保持符号,-1 / float('inf')产生 -0.01 / float(-inf)产生 -0.01 / float('inf')产生 0.0-1/ float(-inf)产生 0.0。此外,-1 / float('inf')1,你必须手动检查的迹象,如果你不想它是真的。

我发现了一个到目前为止还没有人提到的警告。我不知道它是否会经常出现在实际情况中,但这里是为了完整性。

通常,计算一个数的模无穷大会返回一个浮点数,而分数的模无穷大会返回 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上看到。

更新: 这将是 在 Python 3.8中修复

一个非常糟糕的警告: 零分

在一个 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

所以要小心!