为什么 g++(4.6 和 4.7)将此除法的结果提升为双精度?我可以阻止吗?

2023-12-05

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

我发现我的浮点代码速度较慢,在使用 Intel 的 Vtune Amplifier 进行调查后,我发现 g++ 正在生成额外的 x86 指令(cvtps2pd/cvtpd2ps 和 unpcklps/unpcklpd),以将一些中间结果从 float 转换为 double,然后再转换回来。此应用程序的性能下降了近 10%。

在使用 -Wdouble-promotion 标志(顺便说一句,-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 -Wdouble-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;
}

我意识到 c++11 标准允许编译器自行决定。但为什么顺序很重要呢?

我可以明确指示 g++ 仅使用浮点数进行此计算吗?

编辑:由迈克·西摩解决。需要使用 std::log 来确保获取日志的重载版本,而不是调用 Cdouble log(double)。不会为分离的语句生成警告,因为这是转换而不是升级。


问题是

log(r)

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

You want

std::log(r)

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 g++(4.6 和 4.7)将此除法的结果提升为双精度?我可以阻止吗? 的相关文章

随机推荐