为什么g ++(4.6和4.7)将此除法的结果推广为double?我可以阻止它吗?

amc*_*ley 4 c++ templates g++ intel-vtune floating-point-precision

我正在编写一些模板化代码来使用浮点数和双精度数据算法进行基准测试,以便与GPU实现进行比较.

我发现我的浮点代码速度较慢,在调查使用英特尔的Vtune放大器后,我发现g ++正在生成额外的x86指令(cvtps2pd/cvtpd2ps和unpcklps/unpcklpd),将一些中间结果从float转换为double然后再转回.此应用程序的性能下降几乎为10%.

在使用标志-Wdouble-promotion(其中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 -Wouble-promotion -Wextra -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;
}
Run Code Online (Sandbox Code Playgroud)

我意识到c ++ 11标准允许编译器自行决定.但为什么订单很重要?

我是否可以明确指示g ++仅为此计算使用浮点数?

编辑:Mike Seymour解决.需要使用std ::日志,以确保拿起日志的重载版本,而不是调用C double log(double).未为分隔的语句生成警告,因为这是转换而不是促销.

Mik*_*our 5

问题是

log(r)
Run Code Online (Sandbox Code Playgroud)

在这个实现中,似乎log全局命名空间中唯一的是C库函数double log(double).请记住,没有指定C++库中的C库头是否将其定义转储到全局命名空间中namespace std.

你要

std::log(r)
Run Code Online (Sandbox Code Playgroud)

确保C++库定义的额外重载可用.