180

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

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

这似乎是必须有一些警告的功能类型。有什么我应该注意的吗?

4

5 回答 5

102

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

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

不平等比较

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

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

平等比较

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

当然+inf不等于-inf,包括NaN它自己在内的一切都不等于NaN

无穷大的计算

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

  • 当乘以零时,结果未定义,它产生NaN
  • 当将任何数字(除了无穷大本身)除以无穷大时,得到0.0-0.0²。
  • 当正或负无穷除以正或负无穷时(包括模),结果是不确定的,所以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.pow, powor**很棘手,因为它的行为不应该如此。当两个实数的结果太高而无法容纳双精度浮点数时(它应该返回无穷大),它会引发溢出异常,但是当输入为infor时-inf,它会正确运行并返回infor 0.0。当第二个参数是NaN时,它返回NaN,除非第一个参数是1.0。还有更多问题,文档中并未涵盖所有问题。
  • math.exp遇到与 相同的问题math.pow。解决此溢出问题的解决方案是使用与此类似的代码:

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

笔记

注 1:作为附加警告,根据 IEEE 标准的定义,如果您的计算结果下溢或下溢,则结果不会是下溢或下溢错误,而是正或负无穷大:1e308 * 10.0yield inf

注意 2:因为任何带有NaN返回值的计算NaN和任何与 的比较NaN,包括NaN它本身false,都应该使用该math.isnan函数来确定一个数字是否确实是NaN

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

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

¹) 最近意味着从3.2 版开始。
²) 浮点数支持正负零,所以:x / float('inf')保持它的符号和-1 / float('inf')yield -0.01 / float(-inf)yield -0.01 / float('inf')yield0.0-1/ float(-inf)yield 0.0。此外,0.0 == -0.0istrue,如果您不希望它为真,则必须手动检查该符号。

于 2009-10-27T00:33:01.467 回答
98

您仍然可以从涉及以下的简单算术中获得非数字 (NaN) 值inf

>>> 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值默默地注入到您的计算中。

于 2009-10-27T00:31:36.357 回答
3

C99也是如此。

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

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

于 2009-10-27T00:25:05.230 回答
3

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

通常,计算一个模无穷大的数字会返回一个浮点数,但一个分数模无穷大返回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 中修复

于 2018-02-28T04:07:18.830 回答
3

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

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

所以要小心!

于 2019-10-10T15:35:53.947 回答