Почему sqrt в глобальном масштабе намного медленнее, чем std::sqrt в MinGW?

Рассмотрим следующий код:

#include <cmath>
#include <cstdio>

const int COUNT = 100000000;

int main()
{
    double sum = 0;
    for (int i = 1; i <= COUNT; ++i)
        sum += sqrt(i);
    printf("%f\n", sum);
    return 0;
}

На моем компьютере он работает 5,5 с. Однако, если я изменю sqrt на std::sqrt, он будет работать только 0,7 с.

Я знаю, что если я использую sqrt, я использую функцию из библиотеки C, а если я использую std::sqrt, я использую функцию из <cmath>.

Но <cmath> не определяет его для int, и если я изменю тип i на double, они будут работать с одинаковой скоростью. Таким образом, компилятор не оптимизирует int. Кажется, это происходит только с sqrt в Windows.

Так почему же std::sqrt намного быстрее, чем sqrt, но не другие функции? А почему в линуксе их нет?


person infmagic2047    schedule 24.10.2014    source источник
comment
Какая версия компилятора и это MinGW(.org) или MinGW-w64?   -  person rubenvb    schedule 24.10.2014
comment
В C++11 добавлена ​​поддержка целочисленных аргументов для std:sqrt: en.cppreference.com/ w/cpp/числовой/математика/sqrt   -  person Paul R    schedule 24.10.2014
comment
Очевидно, что если вы выполняете математику с doubles, это займет заметно больше времени, чем только с ints.   -  person rsethc    schedule 24.10.2014
comment
@PaulR, но разве это не просто приводит целочисленный параметр к double (по крайней мере, согласно cppreference, или, может быть, я неправильно его понимаю), что эквивалентно тому, что произойдет с ::sqrt?   -  person eerorika    schedule 24.10.2014
comment
Вы смотрели на сгенерированный машинный код?   -  person Kerrek SB    schedule 24.10.2014
comment
И ваши параметры компиляции компилятора ...? Когда вы публикуете, что определенный фрагмент кода медленный/быстрый, вы должны опубликовать компилятор и параметры компилятора, используемые для сборки вашего примера. В противном случае это пустая трата времени на размышления о том, в чем проблема.   -  person PaulMcKenzie    schedule 24.10.2014
comment
Я скомпилировал его с g++ test.cpp -o test, без флага оптимизации. Я протестировал его с помощью компилятора с mingw.org, как 32-битного, так и 64-битного. Я не использую С++ 11.   -  person infmagic2047    schedule 24.10.2014
comment
@ yyt16384 - Никаких оптимизаций == бессмысленные результаты.   -  person PaulMcKenzie    schedule 24.10.2014
comment
@ yyt16384 yyt16384 Как насчет того, чтобы попробовать с оптимизацией, и если разница сохранится, показать какую-нибудь сборку (-S для gcc)?   -  person filmor    schedule 24.10.2014
comment
@ yyt16384: я не использую С++ 11 - это не значит, что ваша библиотека не работает. Моя версия GCC включает новую перегрузку независимо от того, укажете ли вы C++11 или нет.   -  person Mike Seymour    schedule 24.10.2014
comment
@rsethc: Честно говоря, это очевидно только при наличии соответствующих знаний. Моя жена, например, не могла сказать. В то же время многое из того, что для нее очевидно, для меня — египетские иероглифы. Таким образом, я, следовательно, удалил очевидное из своей грамматики, потому что очевидность всегда и всегда зависит от контекста и знания, которого нет в ваших генах, и это вообще никогда не является причиной. Я захожу так далеко, чтобы сказать, что использование очевидного часто указывает на недостаток знаний или отсутствие навыков объяснения.   -  person Sebastian Mach    schedule 24.10.2014
comment
@phresnel: я бы посчитал это вопиюще очевидным по сравнению с тем, как машина обрабатывает инструкции, сгенерированные в пространстве имен, по сравнению с скомпилированными для оптимизации для глобальной области видимости, что является чепухой. (Вещи в пространствах имен, насколько мне известно, не обрабатываются иначе, чем вещи вне пространств имен.)   -  person rsethc    schedule 25.10.2014
comment
@rsethc: Очевидно, что если это очевидно для всех, то заданного здесь вопроса не существует. Между прочим, для меня совершенно, совершенно и совершенно очевидно, что вещи обрабатываются одинаково, не говоря уже о том, насколько глубоко они вложены друг в друга. пространства имен. Для вас это явно не так. Уловил мою мысль?   -  person Sebastian Mach    schedule 25.10.2014
comment
@phresnel Хорошо, что вопроса здесь не будет, но я не сказал, что к ним применяются одинаково. Но да, я понял, я полагаю, это очевидно для меня, но не для спрашивающего.   -  person rsethc    schedule 25.10.2014
comment
@rsethc: В частности, вы написали, что насколько вам известно, к ним относятся одинаково. Так что, очевидно, это не так очевидно. В любом случае, хорошего воскресенья :)   -  person Sebastian Mach    schedule 26.10.2014
comment
@phresnel: Спасибо, и вам тоже.   -  person rsethc    schedule 26.10.2014


Ответы (1)


Это типичная ситуация, в которой переключатель -fdump-tree-* может дать некоторое представление о том, что происходит:

g++ -fdump-tree-optimized example1.cc

и вы получите файл example1.cc.165t.optimized. Где-то внутри:

<bb 3>:
_5 = (double) i_2;
_6 = sqrt (_5);
sum_7 = sum_1 + _6;
i_8 = i_2 + 1;

Компилятор (gcc v4.8.3) выполняет математические операции с doubles.

Заменив sqrt на std::sqrt, вы получите:

<bb 3>:
_5 = std::sqrt<int> (i_2);
sum_6 = sum_1 + _5;
i_7 = i_2 + 1;

Теперь он использует другую перегрузку sqrt для целых чисел (i_2 — это int, а sum_6 — это double).

Как говорит Майк Сеймур в comment, GCC использует новую перегрузку независимо от того, укажете ли вы C++11 или нет.

Во всяком случае, под Linux нет заметной разницы в производительности между двумя реализациями.

В Windows (MinGW) это отличается, поскольку sqrt(double) вызывает msvcrt.

person manlio    schedule 24.10.2014