下面的代码导致执行print语句:
import numpy as np
import math
foo = np.array([1/math.sqrt(2), 1/math.sqrt(2)], dtype=np.complex_)
total = complex(0, 0)
one = complex(1, 0)
for f in foo:
total = total + pow(np.abs(f), 2)
if(total != one):
print str(total) + " vs " + str(one)
print "NOT EQUAL"
然而,我输入的[1/math.sqrt(2), 1/math.sqrt(2)]
导致total
是one
:
(1+0j) vs (1+0j) NOT EQUAL
这是不是与NumPy和Python的复杂类型混合在一起?
3条答案
按热度按时间u0sqgete1#
当使用浮点数时,重要的是要记住,使用这些数字永远不会准确,因此计算每次都会受到舍入误差的影响。这是由floating point arithmetic * 的设计造成的,目前在资源有限的计算机上进行高任意精度数学运算的最可行的方法。你不能使用浮点数精确计算(这意味着你几乎没有其他选择),因为你的数字必须在某个地方被截断以适应合理的内存量(在大多数情况下最多64位),这个截断是通过四舍五入来完成的(见下面的例子)。
为了正确处理这些缺点,你不应该为了相等而与浮点数进行比较,而是为了接近。Numpy为此提供了两个函数:
np.isclose
用于单个值的比较(或数组的逐项比较),np.allclose
用于整个数组。后者是一个np.all(np.isclose(a, b))
,所以你得到一个数组的单个值。但有时四舍五入是非常可行的,并与我们的analytical期望相匹配,例如:
在平方之后,值的大小将被减小以适合给定的内存,因此在这种情况下,它被四舍五入到我们期望的大小。
这两个函数具有内置的绝对和相对公差(您也可以给予其作为参数),用于比较两个值。默认情况下,它们是
rtol=1e-05
和atol=1e-08
。另外,不要将不同的包与它们的类型混合在一起。如果使用Numpy,请使用Numpy-Types和Numpy-Functions。这也将减少舍入误差。
顺便说一句:当处理指数相差很大的数字时,舍入错误的影响更大。
dzhpxtsq2#
我想,与真实的相同的考虑也适用:永远不要假设它们可以相等,而是足够接近:
fquxozlt3#
TLDR:
比较浮点数或复数的正确方法是:
这基本上是
np.isclose()
在幕后所做的,其中np.isclose()
是优选的,因为它关注无穷大、非数字等。详情:
这个问题的特殊情况并不特定于复数。如果你替换
其浮点等价物
你会得到完全相同的结果:
@bereal建议的标准
abs(a-b) < epsilon
在某些情况下有效,但如果你在不同的尺度上观察误差:你会看到,对于大的数字,它是线性增加的(这并不奇怪,因为浮点数只为float 64保留了15个十进制数字),所以使用相对差而不是绝对差会更合理:
它解决了错误增加的问题,但即使是快速浏览也会发现
a==0
的问题。不管你喜欢哪种口味:·
abs(a-b)/max(a,b)
(用于math.isclose()
),·
abs(a-b)/(a+b)
或者什么的,他们都有同样的问题:当
a
和/或b
为零时,它们失效。为了解决这个问题,通常的做法是有两个“ε”:一个绝对的epsilon(又名
atol
,绝对容差)用于与零进行比较,一个相对的epsilon(又名rtol
,相对容差)用于与其他任何东西进行比较。作为底线:
·
np.isclose()
做abs(a-b) <= atol + rtol * abs(b)
·
math.isclose()
做abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
math
版本更对称,但numpy
版本更快。