Я писал некоторый шаблонный код для сравнения числового алгоритма с использованием чисел с плавающей запятой и двойных чисел, чтобы сравнить их с реализацией графического процессора.
Я обнаружил, что мой код с плавающей запятой был медленнее, и после исследования с использованием Vtune Amplifier от Intel я обнаружил, что g ++ генерирует дополнительные инструкции x86 (cvtps2pd / cvtpd2ps и unpcklps / unpcklpd) для преобразования некоторых промежуточных результатов из float в double и затем обратно. Ухудшение производительности составляет почти 10% для этого приложения.
После компиляции с флагом -Wdouble-promoing (который BTW не включен с -Wall или -Wextra), достаточно g ++ предупредил меня, что результаты были продвинуты.
Я сократил это до простого теста, показанного ниже. Обратите внимание, что порядок кода C ++ влияет на сгенерированный код. Составной оператор (T d1 = log (r) / r;) выдает предупреждение, в то время как разделенная версия — нет (T d = log (r); d / = r;).
Следующее было скомпилировано как с g ++ — 4.6.3-1ubuntu5, так и с g ++ — 4.7.3-2ubuntu1 ~ 12.04 с одинаковыми результатами.
Флаги компиляции:
g ++ — 4.7 -O2 -Двойное продвижение -Вэкстра -Wall -pedantic -Werror -std = c ++ 0x test.cpp -o test
#include <cstdlib>
#include <iostream>
#include <cmath>
template <typename T>
T f()
{
T r = static_cast<T>(0.001);
// Gives no double promotion warning
T d = log(r);
d/=r;
// Promotes to double
T d1 = log(r)/r;
return d+d1;
}
int main()
{
float f1 = f<float>();
std::cout << f1 << std::endl;
}
Я понимаю, что стандарт c ++ 11 допускает усмотрение компилятора здесь. Но почему порядок имеет значение?
Могу ли я явно указать g ++ использовать поплавки только для этого вычисления?
РЕДАКТИРОВАТЬ: решено Майком Сеймуром. Нужно использовать std :: log для обеспечения загрузки перегруженной версии log вместо вызова C double log(double)
, Предупреждение не было сгенерировано для отдельного оператора, потому что это конверсия, а не продвижение.
Проблема в
log(r)
В этой реализации кажется, что единственным log
в глобальном пространстве имен находится функция библиотеки C, double log(double)
, Помните, что не указано, будут ли заголовки C-библиотеки в библиотеке C ++ выводить свои определения в глобальное пространство имен, а также namespace std
,
Ты хочешь
std::log(r)
чтобы гарантировать наличие дополнительных перегрузок, определенных библиотекой C ++.
Других решений пока нет …