【发布时间】:2009-10-27 00:12:06
【问题描述】:
所以Python有正无穷和负无穷:
float("inf"), float("-inf")
这似乎是需要注意的功能类型。有什么我应该注意的吗?
【问题讨论】:
-
请注意,常量
1e309将被解释为+inf,-1e309将被解释为-inf。
所以Python有正无穷和负无穷:
float("inf"), float("-inf")
这似乎是需要注意的功能类型。有什么我应该注意的吗?
【问题讨论】:
1e309 将被解释为+inf,-1e309 将被解释为-inf。
Python's implementation 很好地遵循了IEEE-754 standard,您可以将其用作指导,但它依赖于编译它的底层系统,因此可能会出现platform differences。最近¹,已经应用了一个允许"infinity" as well as "inf" 的修复程序,但这在这里并不重要。
以下部分同样适用于正确实现 IEEE 浮点运算的任何语言,它不仅仅针对 Python。
在处理无穷大和大于> 或小于< 运算符时,以下几点很重要:
+inf在内的任何数字都高于-inf
-inf在内的任何数字都小于+inf
+inf 是 neither 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.pow、pow 或** 很棘手,因为它的行为不符合应有的要求。当两个实数的结果太高而无法容纳双精度浮点数(它应该返回无穷大)时,它会引发溢出异常,但是当输入为inf 或-inf 时,它会正常运行并返回inf或0.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.0,1 / float(-inf) 产生 -0.0,1 / float('inf') 产生 0.0 和 -1/ float(-inf) 产生 0.0 .另外,0.0 == -0.0 is true,如果你不希望它是真的,你必须手动检查标志。
【讨论】:
-1 * float('infinity') == -inf
您仍然可以通过涉及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 或-inf 时,它会返回0.0 或inf。所以它确实在输入为无穷大时正常工作,但在结果应该为无穷大时却不能正常工作。
C99 也是如此。
所有现代处理器使用的 IEEE 754 浮点表示具有几个特殊的位模式,为正无穷(sign=0、exp=~0、frac=0)、负无穷(sign=1、exp=~0、 frac=0) 和许多 NaN(非数字:exp=~0, frac≠0)。
您只需要担心:一些算术可能会导致浮点异常/陷阱,但不仅限于这些“有趣”的常量。
【讨论】:
OverflowError。
我发现了一个迄今为止没有人提到的警告。不知道实际情况会不会经常出现,这里是为了完整起见。
通常,计算模无穷大的数字会将自身返回为浮点数,但模无穷大的分数返回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。
【讨论】:
一个非常糟糕的警告:除以零
在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
所以要小心!
【讨论】: