Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么g++;(4.6和4.7)将该划分的结果提升到双倍?我能阻止它吗?_C++_Templates_G++_Floating Point Precision_Intel Vtune - Fatal编程技术网

C++ 为什么g++;(4.6和4.7)将该划分的结果提升到双倍?我能阻止它吗?

C++ 为什么g++;(4.6和4.7)将该划分的结果提升到双倍?我能阻止它吗?,c++,templates,g++,floating-point-precision,intel-vtune,C++,Templates,G++,Floating Point Precision,Intel Vtune,我正在编写一些模板代码,用浮点和双精度对数值算法进行基准测试,以便与GPU实现进行比较 我发现我的浮点代码速度较慢,在使用英特尔Vtune放大器进行调查后,我发现g++生成了额外的x86指令(cvtps2pd/cvtpd2ps和unpcklps/unpcklpd),以将一些中间结果从浮点转换为双精度,然后再转换回来。此应用程序的性能下降近10% 在使用标志-Wdouble promotion(顺便说一句-Wall或-Wextra不包含该标志)编译之后,g++警告我结果正在升级 我将其简化为一个简

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

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

在使用标志-Wdouble promotion(顺便说一句-Wall或-Wextra不包含该标志)编译之后,g++警告我结果正在升级

我将其简化为一个简单的测试用例,如下所示。请注意,C++代码的排序会影响生成的代码。复合语句(td1=log(r)/r;)会产生警告,而单独的版本不会产生警告(td=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;
}
#包括
#包括
#包括
模板
tf()
{
Tr=静态_铸造(0.001);
//没有双重晋升警告
td=对数(r);
d/=r;
//提升到双倍
T d1=对数(r)/r;
返回d+d1;
}
int main()
{
float f1=f();
问题是

log(r)

在这个实现中,全局命名空间中唯一的<代码>日志<代码>是C库函数,<代码>双日志(double)< /C>。记住,没有指定C++库中的C库头是否将它们的定义转储到全局命名空间中,以及<代码>命名空间STD< /COD> 你想要

std::log(r)

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

看起来您是正确的。我认为日志将调用重载版本浮动日志(浮点X)。因此,为什么分离的版本不产生促销?至于为什么<代码> t d=log(r);
没有警告,可能是gcc优化了
(float)log((double)x)
logf(x)
当x是浮点时。@amckinley:这会产生转换,而不是提升。您需要
-Wconversion
来捕捉它。好的,我发现缺少警告实际上是问题所在。在使用objdump检查生成的代码后,这两个语句使用额外的cvtps2pd/cvtpd2ps和unpcklps生成几乎完全相同的代码/取消CKLPD指令。所以问题是
双日志(double)
正在被调用,而且在第二种情况下,g++没有警告双重升级。编辑:显然不应该这样做。我需要-Wconversion才能捕捉到这一点。@marglisse:这不太可能,除非编译器知道两个操作对所有输入都给出完全相同的结果(它们可能不会)。这不是在这里发生的(至少在我的GCC版本中是这样),用
-Wconversion
编译会证明这一点。
-Wconversion
也会产生警告