Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.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++ 编译器能否优化多个相同的函数调用_C++_Function_Optimization - Fatal编程技术网

C++ 编译器能否优化多个相同的函数调用

C++ 编译器能否优化多个相同的函数调用,c++,function,optimization,C++,Function,Optimization,关于SO上的“冗余函数调用”,有很多关于编译器优化的问题和很好的答案(我不会发布链接),但是,我在SO上的多个相同函数调用上找不到任何东西 假设我有这样一个代码片段: void fairlyComplexFunction(const double &angle) { //do stuff and call "sin(angle)" very often in here } 调用sin(angle)是一个相当昂贵的操作,因为angle是fairlyComplexFunction范

关于SO上的“冗余函数调用”,有很多关于编译器优化的问题和很好的答案(我不会发布链接),但是,我在SO上的多个相同函数调用上找不到任何东西

假设我有这样一个代码片段:

void fairlyComplexFunction(const double &angle)
{
    //do stuff and call "sin(angle)" very often in here
}
调用
sin(angle)
是一个相当昂贵的操作,因为
angle
fairlyComplexFunction
范围内的常量,每次调用sine都会得到相同的结果,因此只调用一次是更好的方法:

void fairlyComplexFunction(const double &angle)
{
    const double sineOfAngle = sin(angle);
    //do stuff and use sineOfAngle very often in here
}

编译器在任何方面都能检测到这样的东西并对我进行优化吗?或者第二个例子是更好的方法吗?

如果它能证明
sin
没有任何副作用,它可以对它进行优化


但即使可以,您的第二个版本也向读者和您自己清楚地表明,所有代码都应该使用相同的值,并且没有一个使用是bug;错误和不确定性的空间更小。

正如注释中所述,如果编译器能够检测到调用的函数是纯函数(没有副作用,没有i/o,…),那么它可能能够优化这些东西

使用g++的一个小示例():

#include <cmath>

extern double g (double);

template <double (*F) (double)>
double f1 (double angle) {
  double x = 3 * F(angle) + F(angle);
  double y = F(angle) + F(angle) * F(angle);
  return x + y * F(angle);
}

template double f1<sin> (double);
template double f1<g> (double);
您可以看到,在使用
sin
的实例化中,g++只执行一个函数调用(
callsin
),而在使用
g
的实例化中,您有6个调用

因此,,编译器可能会对pure函数的多个调用进行一些优化,但我不会依赖它**并使用第二个示例中的显式中间变量

*我删除了大部分生成的指令,但显示了所有
call
指令


**
clang
即使使用
-O3
(但它使用
-ffast math
)也不会优化此功能。

自己编译并查看输出?@KerrekSB首先,我真的不太擅长查看和理解汇编语言。另外,当我编译它时,它不工作,这并不意味着其他编译器可能无法完成。原则上,如果编译器可以确保所讨论的函数是纯函数(没有副作用,影响其输出的唯一因素是其输入),那么它就可以轻松地消除多个调用。然而,证明C++中的函数是纯的并不总是简单或容易的。@ yZt在这种情况下,Sin(x)确实是纯函数,所以我猜想它可以“原理工作”。@ Pel13131:不仅是纯函数,而且是实现提供的函数。这不仅仅是一个“原则上可以工作”,我真的希望如此。我甚至希望对
sin(x)
cos(x)
的调用被合并,即使它们不是相同的函数(!)非常感谢,这是一个非常彻底的回答。我觉得有趣的是,这不是用-O3优化的,但你需要-F的数学,因为这应该是多余的。此外,用户“必须知道这一点”并可能最终得到未完全优化的代码也是一件棘手的事情…@phil13131:从理论上讲,两次调用之间的舍入模式可能会改变,这将使函数实际上不纯净。使用
-ffast math
编译器可以忽略舍入模式的更改。
double f1<&sin>(double):
        subq    $8, %rsp
        call    sin
        ...
        ret

double f1<&(g(double))>(double):
        subq    $40, %rsp
        movsd   %xmm0, (%rsp)
        call    g(double)
        movsd   %xmm0, 8(%rsp)
        movsd   (%rsp), %xmm0
        call    g(double)
        movsd   8(%rsp), %xmm1
        mulsd   .LC0(%rip), %xmm1
        ...
        call    g(double)
        movsd   %xmm0, 16(%rsp)
        movsd   (%rsp), %xmm0
        call    g(double)
        movsd   %xmm0, 24(%rsp)
        movsd   (%rsp), %xmm0
        call    g(double)
        mulsd   24(%rsp), %xmm0
        movsd   16(%rsp), %xmm2
        ...
        call    g(double)
        mulsd   16(%rsp), %xmm0
        addsd   8(%rsp), %xmm0
        ...