python - C++ vs python numpy 复杂数组性能
问题描述
谁能告诉我为什么这两个程序在运行时间上有巨大差异?我只是将两个大型复杂数组相乘并比较 python (numpy) 和 c++ 中的时间。我正在使用带有 g++ 的 -O3 标志来编译这个 C++ 代码。我发现只有当我在 C++ 中使用复杂的浮点数时才会出现巨大的差异,它在 numpy 中的速度要快 20 倍以上。
蟒蛇代码:
import numpy as np
import time
if __name__ == "__main__":
# check the data type is the same
a = np.zeros((1), dtype=np.complex128)
a[0] = np.complex(3.4e38,3.5e38)
print(a)
b = np.zeros((1), dtype=np.complex64)
b[0] = np.complex(3.4e38,3.5e38)
print(b) # imaginary part is infinity
length = 5000;
A = np.ones((length), dtype=np.complex64) * np.complex(1,1)
B = np.ones((length), dtype=np.complex64) * np.complex(1,0)
num_iterations = 1000000
time1 = time.time()
for _ in range(num_iterations):
A *= B
time2 = time.time()
duration = ((time2 - time1)*1e6)/num_iterations
print(duration)
C++ 代码:
#include <iostream>
#include <complex>
#include <chrono>
using namespace std::chrono;
using namespace std;
int main()
{
// check the data type is the same
complex<double> a = complex<double>(3.4e38, 3.5e38);
cout << a << endl;
complex<float> b = complex<float>(3.4e38, 3.5e38);
cout << b << endl; // imaginary part is infinity
const int length = 5000;
static complex<float> A[length];
static complex<float> B[length];
for(int i=0; i < length; i++) {
A[i] = complex<float>(1,1);
B[i] = complex<float>(1,0);
}
int num_iterations = 1000000;
auto time1 = high_resolution_clock::now();
for(int k=0; k < num_iterations; k++)
for(int i=0; i < length; i++)
A[i] *= B[i];
auto time2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(time2 - time1);
cout << "average time:" << duration.count() / num_iterations << endl;
}
解决方案
C++ 编译器正在为您做一些额外的检查,以便正确处理 NaN 和其他此类“标准”行为。如果您添加-ffast-math
优化标志,您将获得更理智的速度,但更少的“标准”行为。egcomplex<float>(inf,0)*complex<float>(inf,0)
不会被评估为complex<float>(inf,0)
. 你真的在乎吗?
numpy 正在做有意义的事情,而不是受到对 C++ 标准的狭隘阅读的阻碍。
例如,直到最近的g++ 版本,除非使用,否则以下函数中的后者要快得多-ffast-math
。
complex<float> mul1( complex<float> a,complex<float> b)
{
return a*b;
}
complex<float> mul2( complex<float> a,complex<float> b)
{
float * fa = reinterpret_cast<float*>(&a);
const float * fb = reinterpret_cast<float*>(&b);
float cr = fa[0]*fb[0] - fa[1]*fb[1];
float ci = fa[0]*fb[1] + fa[1]*fb[0];
return complex<float>(cr,ci);
}
您可以在https://godbolt.org/z/kXPgCh上对此进行试验以 获取程序集输出以及前一个函数如何默认调用 __mulsc3
PS 准备好迎接对 C++ 标准所说的另一波愤怒了std::complex<T>
吗?你能猜出std::norm默认是如何实现的吗?一起玩。点击链接并花十秒钟思考它。
剧透:它可能正在使用 sqrt 然后对其进行平方。
推荐阅读
- amazon-web-services - 在 AWS Sagemaker 中训练 keras 模型
- blazor - 基于相同代码的 2 个不同的 Blazor 页面
- java - 为什么当我输入不是整数时,catch 不起作用
- laravel - laravel eloquent belongsToMany 如何与内部类常量建立关系?
- flutter - Flutter Web - 使用电话选择图像
- html - 无需更改布局即可访问占位符文本
- javascript - 在空手道 dsl 中使用 file.js
- python - 根据列值在熊猫数据框中选择行时出错
- python - 连接到 SuperSet 中的子项目
- unity3d - 用于 VR 的 Unity 中的餐巾纸