这似乎有效:
import numpy as np
def compl_div(A,B):
A,B = np.asarray(A),np.asarray(B)
Ba = np.abs(B)[...,None]
A = (A[...,None].view(float)/Ba).view(complex)[...,0]
B = (B.conj()[...,None].view(float)/Ba).view(complex)[...,0]
return A*B
a = np.random.randn(10000)
b = np.random.randn(10000)
A = a.astype(complex)
B = b.astype(complex)
print((compl_div(A,B)==a/b).all())
print((np.sqrt(b*b)==np.abs(b)).all())
ac = a.view(complex)
bc = b.view(complex)
print(np.allclose(compl_div(ac,bc),ac/bc))
示例运行:
True # complex without imag exactly equal float
True # reason it works
True # for nonzeron imag part do we actually get complex division
解释:
让我们用浮点除法的复数写成///
(x+iy)///r = x/r + iy/r
numpy似乎将复数除法A/B
实现为A*(1/B)
(可以将1/B
计算为B.conj()///(B.conj()*B)
),事实上,A/B似乎总是等于a*(1/b)
相反,我们使用(A///abs(B)) * (B.conj()///abs(B))
作为abs(B)^2 = B*B.conj()
这在数学上是等价的,但在数字上不等价。
现在,如果我们有abs(B) == abs(b)
,那么A///abs(B) = a/abs(b)
和B///abs(B) = sign(b)
,我们可以看到compl_div(A,B)
确实精确地返回a/b
。
由于 abs(x+iy) = sqrt(x^2+y^2)
,我们需要证明 sqrt(b*b) = abs(b)
。除非在平方过程中出现上溢或下溢、平方为非规格化数或实现不符合IEEE标准,否则这是可证明的真实。