为何NumPy中复数共轭运算速度与复数乘法相当?
复数共轭运算为何和复数乘法速度相当?
我对复数共轭运算速度接近复数乘法感到困惑,以下是测试代码和运行结果:
import numpy as np def op0(x): return np.conj(x) def op1(x0, x1): return x0 * x1 def op2(x0, x1): x0[:] = x1 for N in (50, 500, 5000): print(f"\nshape = ({N}, {N})") x0 = np.random.randn(N, N) + 1j*np.random.randn(N, N) x1 = np.random.randn(N, N) + 1j*np.random.randn(N, N) %timeit op0(x0) %timeit op1(x0, x1) %timeit op2(x0, x1)
运行结果:
shape = (50, 50) 3.55 µs ± 143 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 4.85 µs ± 261 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 1.85 µs ± 116 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) shape = (500, 500) 1.52 ms ± 60.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 1.96 ms ± 133 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 299 µs ± 50.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) shape = (5000, 5000) 163 ms ± 4.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) 185 ms ± 11.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) 39.8 ms ± 399 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
为什么翻转x.imag的符号会这么耗时?从底层逻辑看,这明明比(a + j*b)*(c + j*d)这类包含多次乘法和加法的运算简单得多。
关键原因解析
- 内存带宽是核心瓶颈:
np.conj()默认会创建新数组,需要分配内存并复制所有数据(实部直接拷贝,虚部取反后拷贝)。复数乘法同样需要创建新数组并写入计算结果,两者的内存操作开销占比很高——对于大数组,内存读写的耗时远超过计算本身的差异,导致两者速度接近。 - 硬件优化的差异:现代CPU有专门的SIMD指令优化复数乘法,能批量高效完成运算;而复数共轭的操作虽然简单,但对应的SIMD优化可能不够充分,或者内存开销掩盖了计算上的优势。
- numpy实现路径:
np.conj()的内部实现可能复用了通用的数组处理框架,没有针对“仅翻转虚部”做极致精简。对比原地赋值op2的速度,就能看出无计算的纯内存拷贝/修改要快得多,进一步说明内存操作是影响速度的关键。
环境:Windows 10 x64,numpy 1.23.5,Python 3.10.4
内容的提问来源于stack exchange,提问作者OverLordGoldDragon
相关产品推荐
相关产品推荐

