所以 Python 有正无穷大和负无穷大:
float("inf"), float("-inf")
这似乎是一个需要注意的特性类型。有什么我需要注意的吗?
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)值:
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值静默地注入到计算中。
OverflowError
Python 的实现 很好地遵循了 IEEE-754标准,您可以将其用作指导,但是它依赖于编译它所依赖的底层系统,因此可能会出现 平台差异。最近,应用了一个允许 “无穷”和“ inf”的修复程序,但是这个修复程序在这里并不重要。
以下各节同样适用于正确实现 IEEE 浮点运算的任何语言,它不仅仅适用于 Python。
当处理无穷大和大于或小于 <运算符时,计数如下:
<
+inf
-inf
NaN
相等时,+inf和 +inf是相等的,-inf和 -inf也是相等的。这是一个备受争议的问题,您可能会觉得有争议,但它是在 IEEE 标准中的,Python 的行为就是这样。
当然,+inf不等于 -inf,任何东西,包括 NaN本身,都不等于 NaN。
除非两个操作数都是无穷大,否则大多数有无穷大的计算都会产生无穷大,当运算除法或模或乘法为零时,需要记住一些特殊的规则:
当乘以结果未定义的零时,它生成 NaN
当任何数字(除了无穷大本身)除以无穷大时,它产生 0.0或 -0.02。
0.0
-0.0
当把(包括模)正无穷大或负无穷大除以正无穷大或负无穷大时,结果是未定义的,因此 NaN。
在减法时,结果可能令人惊讶,但按照 数学常识:
当做 inf - inf时,结果是未定义的: NaN;
inf - inf
当做 inf - -inf时,结果是 inf;
inf - -inf
当做 -inf - inf时,结果是 -inf;
-inf - inf
当执行 -inf - -inf时,结果是未定义的: NaN。
-inf - -inf
在补充时,它也可能同样令人惊讶:
当做 inf + inf时,结果是 inf;
inf + inf
当做 inf + -inf时,结果是未定义的: NaN;
inf + -inf
当做 -inf + inf时,结果是未定义的: NaN;
-inf + inf
当做 -inf + -inf时,结果是 -inf。
-inf + -inf
使用 math.pow、 pow或者 **是很棘手的,因为它们的行为并不像它们应该的那样。当两个实数的结果太高而无法满足双精度浮点数时(它应该返回无穷大) ,它会抛出溢出异常,但是当输入为 inf或 -inf时,它的行为正确并返回 inf或 0.0。当第二个参数是 NaN时,它返回 NaN,除非第一个参数是 1.0。还有更多的问题,不是所有的 pow0。
math.pow
pow
**
1.0
math.exp和 math.pow有相同的问题。解决此溢出问题的一个解决方案是使用与下面类似的代码:
math.exp
try: res = math.exp(420000) except OverflowError: res = float('inf')
注1: 作为一个附加的警告,根据 IEEE 标准的定义,如果你的计算结果低于或溢出,结果将不是低于或溢出错误,而是正的或负的无穷大: 1e308 * 10.0产生 inf。
1e308 * 10.0
注意2: 因为使用 NaN的任何计算都返回 NaN,并且与 NaN的任何比较(包括 NaN本身)都是 false,所以应该使用 math.isnan函数来确定一个数字是否确实是 NaN。
false
math.isnan
注3: 尽管 Python 支持编写 float('-NaN'),但是这个符号被忽略了,因为在 NaN内部不存在符号。如果你除以 -inf / +inf,结果是 NaN,而不是 -NaN(没有这样的东西)。
float('-NaN')
-inf / +inf
-NaN
注意4: 小心地依赖上述任何一个,因为 Python 依赖于它所编译的 C 或 Java 库,并非所有底层系统都正确地实现了所有这些行为。如果您想要确定,那么在进行计算之前测试无穷大。
1)最近指自 版本3.2以来。 2)浮点数支持正负零,因此: x / float('inf')保持符号,-1 / float('inf')产生 -0.0,1 / float(-inf)产生 -0.0,1 / float('inf')产生 0.0,-1/ float(-inf)产生 0.0。此外,-1 / float('inf')1,你必须手动检查的迹象,如果你不想它是真的。
x / float('inf')
-1 / float('inf')
1 / float(-inf)
1 / float('inf')
-1/ float(-inf)
我发现了一个到目前为止还没有人提到的警告。我不知道它是否会经常出现在实际情况中,但这里是为了完整性。
通常,计算一个数的模无穷大会返回一个浮点数,而分数的模无穷大会返回 nan(而不是一个数)。这里有一个例子:
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/x
x = 1e-323
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
所以要小心!