Почему g ++ (4.6 и 4.7) продвигает результат этого деления в два раза? Могу ли я остановить это?

Я писал некоторый шаблонный код для сравнения числового алгоритма с использованием чисел с плавающей запятой и двойных чисел, чтобы сравнить их с реализацией графического процессора.

Я обнаружил, что мой код с плавающей запятой был медленнее, и после исследования с использованием 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), Предупреждение не было сгенерировано для отдельного оператора, потому что это конверсия, а не продвижение.

4

Решение

Проблема в

log(r)

В этой реализации кажется, что единственным log в глобальном пространстве имен находится функция библиотеки C, double log(double), Помните, что не указано, будут ли заголовки C-библиотеки в библиотеке C ++ выводить свои определения в глобальное пространство имен, а также namespace std,

Ты хочешь

std::log(r)

чтобы гарантировать наличие дополнительных перегрузок, определенных библиотекой C ++.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]