std :: abs (std :: complex) слишком медленный - PullRequest
0 голосов
/ 28 ноября 2018

Почему запуск std::abs на большом сложном массиве примерно в 8 раз медленнее, чем при использовании sqrt и norm?

#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 голосов
/ 28 ноября 2018

Основная причина в том, что abs обрабатывает недополнение и переполнение во время промежуточных вычислений.

Так что, если norm under / overflows, ваша формула возвращает неверный / неточный результат, а abs вернетправильный (например, если ваши входные числа находятся в диапазоне 10 200 , то результат также должен быть около 10 200 . Но ваша формула даст вамinf, или исключение с плавающей запятой, потому что промежуточное значение norm составляет около 10 400 , что выходит за пределы диапазона. Обратите внимание, я предположил, что здесь IEEE-754 имеет 64-битную плавающую точку).

Другая причина в том, что abs может дать немного более точный результат.

Если вам не нужно обрабатывать эти случаи, потому что ваши входные числа "хорошо себя ведут" (и вам не нужен возможный более точный результат), не стесняйтесь использовать вашу формулу.

0 голосов
/ 28 ноября 2018

Я считаю, что эти два не следует воспринимать как идентичные в строгом смысле.

С cppreference на std::abs(std::complex):

Ошибки и специальныедела обрабатываются так, как если бы функция была реализована как std::hypot(std::real(z), std::imag(z))

Также из cppreference на 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))

В целом точность результата может отличаться (из-за обычногобеспорядок с плавающей запятой), и кажется, что функции были спроектированы таким образом, чтобы быть максимально точными.

...