std :: abs(std :: complex)太慢

时间:2018-11-28 11:26:43

标签: c++ std complex-numbers

为什么在大型的复杂数组上运行std::abs的速度比使用sqrtnorm慢大约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
}

2 个答案:

答案 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::normabs(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可能会给出更精确的结果。

如果您不需要处理这些情况,因为您的输入数字“行为良好”(并且不需要可能的更精确结果),请随时使用公式。