为什么在大型的复杂数组上运行std::abs
的速度比使用sqrt
和norm
慢大约8倍?
#include <ctime>
#include <cmath>
#include <vector>
#include <complex>
#include <iostream>
using namespace std;
int main()
{
typedef complex<double> compd;
vector<compd> arr(2e7);
for (compd& c : arr)
{
c.real(rand());
c.imag(rand());
}
double sm = 0;
clock_t tm = clock();
for (const compd& c : arr)
{
sm += abs(c);
}
cout << sm << ' ' << clock() - tm << endl; // 5.01554e+011 - 1640 ms
sm = 0;
tm = clock();
for (const compd& c : arr)
{
sm += sqrt(norm(c));
}
cout << sm << ' ' << clock() - tm << endl; // 5.01554e+011 - 154
sm = 0;
tm = clock();
for (const compd& c : arr)
{
sm += hypot(c.real(), c.imag());
}
cout << sm << ' ' << clock() - tm << endl; // 5.01554e+011 - 221
}
答案 0 :(得分:9)
我认为严格意义上不应将两者视为相同。
来自cppreference on std::abs(std::complex)
:
处理错误和特殊情况就像将函数实现为
std::hypot(std::real(z), std::imag(z))
也来自cppreference on std::norm(std::complex)
:
此函数计算出的范数也称为场范数或绝对平方。
std::abs
提供了复数的欧几里得范数,计算起来成本更高。在某些情况下,例如,如果std::norm
则abs(z1) > abs(z2)
可以用norm(z1) > norm(z2)
代替。
简而言之,在某些情况下,从每个函数获得不同的结果。其中一些可以在std::hypot
中找到。那里的注释还提到了以下内容:
std::hypot(x, y)
等效于std::abs(std::complex<double>(x,y))
通常,结果的准确性可能有所不同(由于通常的浮点混乱),并且似乎以尽可能准确的方式设计了函数。
答案 1 :(得分:4)
主要原因是abs
处理中间计算期间的下溢和上溢。
因此,如果norm
下溢/溢出,您的公式将返回错误/不准确的结果,而abs
将返回正确的结果(例如,如果您输入的数字在10 200 ,那么结果也应该在10 200 左右,但是您的公式会给您inf
或浮点异常,因为中间的{ {1}}大约是10 400 ,超出范围。请注意,我在这里假设是IEEE-754 64位浮点数。
另一个原因是norm
可能会给出更精确的结果。
如果您不需要处理这些情况,因为您的输入数字“行为良好”(并且不需要可能的更精确结果),请随时使用公式。