C / C ++编译器是否会通过重用最近计算的函数结果来优化代码?

问题描述 投票:1回答:3

假设我有一个函数double F(double x),让我们假设为了这个例子,调用F是昂贵的。

假设我写了一个函数f来计算F的平方根:

double f(double x){
   return sqrt(F(x));
}

在第三个函数sum我计算fF的总和:

double sum(double x){
   return F(x) + f(x);
}

由于我想最小化对F的调用,因此上述代码与例如

double sum_2(double x){
   double y = F(x);
   return y + sqrt(y);
}

但由于我很懒惰或愚蠢,或者想让我的代码尽可能清晰,我选择了第一个定义。

C / C ++编译器是否会优化我的代码,因为它意识到F(x)的值可以重用来计算f(x),就像在sum_2中一样?

非常感谢。

c++ c optimization compiler-optimization
3个回答
8
投票

C / C ++编译器是否会通过认识到F(x)的值可以重用来计算f(x)来优化我的代码,就像在sum_2中一样?

也许。两种语言都不需要这样的优化,它们是否允许它取决于F()实现的细节。一般来说,不同的编译器在这种情况下表现不同。

完全合理的是,编译器会将函数f()内联到函数sum()中,这将使它有机会认识到有两个调用F(x)会导致相同的结果。在这种情况下,如果F()没有副作用,那么可以想象编译器只会发出一次对F()的调用,重用结果。

特定实现可以具有可以用于帮助编译器得出这样结论的扩展。但是,如果没有将这样的扩展应用于该问题,我认为编译器不太可能发出只执行一次F()调用并重用结果的代码。


2
投票

您所描述的内容称为memoization,一种(通常)运行时缓存的形式。虽然这可能在编译器中实现,但它通常不在C编译器中执行。

C ++确实有一个聪明的解决方法,使用STL,几年前详细的at this blog post;还有一个稍微更新的SO答案here。值得注意的是,通过这种方法,编译器不会“巧妙地”推断函数的多个相同结果将被重用,但效果大致相同。

有些语言(如Haskell)具有编译时记忆功能,但编译器体系结构与Clang或GCC / G ++完全不同。


1
投票

许多编译器使用提示来确定是否可以重用先前函数调用的结果。一个经典的例子是:

for (int i=0; i < strlen(str); i++)

在没有对此进行优化的情况下,该循环的复杂度至少为O(n2),但在优化之后它可以是O(n)。

gcc,clang和许多其他人可以采取的提示是__attribute__((pure))__attribute__((const)),它们被描述为here。例如,GNU strlen被声明为纯函数。

GCC可以检测pure functions,并建议程序员哪些功能应该是纯粹的结婚。实际上,它会自动执行以下简单示例:

unsigned my_strlen(const char* str) 
{
    int i=0;
    while (str[i])
       ++i;
    return i;
} 

unsigned word_len(const char *str)
{
    for (unsigned i=0 ; i < my_strlen(str); ++i) {
        if (str[i] == ' ')
           return i;
    }
    return my_strlen(str);
}

你可以用qazxsw poi qazxsw poi for gcc。它在整个see the compilation result函数中只调用qazxsw poi一次。 Clang 7.0.0似乎没有执行此优化。

-O3 -fno-inline
© www.soinside.com 2019 - 2024. All rights reserved.