首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >g++ c++11算法性能评估

g++ c++11算法性能评估
EN

Stack Overflow用户
提问于 2013-04-25 18:08:29
回答 2查看 1.8K关注 0票数 13

在编译期间,g++ (4.7.2)和类似版本的计算速度似乎惊人地快。实际上,在我的机器上,运行时要比编译的程序快得多。

对这种行为有合理的解释吗?是否有只适用于编译时才能比实际编译代码更快执行的优化技术?如果是的话,哪一个?

这是我的测试程序和观察结果。

代码语言:javascript
复制
#include <iostream>

constexpr int mc91(int n)
 {

     return (n > 100)? n-10 : mc91(mc91(n+11));

 }

constexpr double foo(double n)
{
   return (n>2)? (0.9999)*((unsigned int)(foo(n-1)+foo(n-2))%100):1;
}

constexpr unsigned ack( unsigned m, unsigned n )
{
    return m == 0
        ? n + 1
        : n == 0
        ? ack( m - 1, 1 )
        : ack( m - 1, ack( m, n - 1 ) );
}

constexpr unsigned slow91(int n) {
   return mc91(mc91(foo(n))%100);
}

int main(void)
{
   constexpr unsigned int compiletime_ack=ack(3,14);
   constexpr int compiletime_91=slow91(49);
   static_assert( compiletime_ack == 131069, "Must be evaluated at compile-time" );
   static_assert( compiletime_91  == 91,     "Must be evaluated at compile-time" );
   std::cout << compiletime_ack << std::endl;
   std::cout << compiletime_91  << std::endl;
   std::cout << ack(3,14) << std::endl;
   std::cout << slow91(49) << std::endl;
   return 0;
}

编译时:

代码语言:javascript
复制
time g++ constexpr.cpp -std=c++11 -fconstexpr-depth=10000000 -O3 

real    0m0.645s
user    0m0.600s
sys     0m0.032s

运行时:

代码语言:javascript
复制
time ./a.out 

131069
91
131069
91

real    0m43.708s
user    0m43.567s
sys     0m0.008s

这里,mc91是常见的mac f91 (可以在维基百科上找到),foo只是一个无用的函数,返回1到100之间的实际值,具有fib运行时的复杂性。

对于91和ackermann函数的缓慢计算,编译器和编译程序都使用相同的参数进行计算。

令人惊讶的是,与执行代码本身相比,程序运行得更快,只需生成代码并在编译器中运行。

EN

回答 2

Stack Overflow用户

发布于 2013-04-25 18:29:25

在编译时,冗余(相同) constexpr调用可以是回忆录,而运行时递归行为不提供此功能。

如果您更改了每个递归函数,例如..。

代码语言:javascript
复制
constexpr unsigned slow91(int n) {
   return mc91(mc91(foo(n))%100);
}

..。对于一个不是constexpr的表单,但是确实在运行时记住了过去的计算:

代码语言:javascript
复制
std::unordered_map< int, boost::optional<unsigned> > results4;
//     parameter(s) ^^^           result ^^^^^^^^

unsigned slow91(int n) {
     boost::optional<unsigned> &ret = results4[n];
     if ( !ret )
     {
         ret = mc91(mc91(foo(n))%100);
     }
     return *ret;
}

你会得到不那么令人惊讶的结果。

编译时:

代码语言:javascript
复制
time g++ test.cpp -std=c++11 -O3

real    0m1.708s
user    0m1.496s
sys     0m0.176s

运行时:

代码语言:javascript
复制
time ./a.out

131069
91
131069
91

real    0m0.097s
user    0m0.064s
sys     0m0.032s
票数 14
EN

Stack Overflow用户

发布于 2013-04-25 18:49:29

追忆

这是一个非常有趣的“发现”,但答案可能比你想象的要简单。

如果所有涉及的值都是在编译时已知的(如果值最终被声明的变量也被声明为constexpr ),则可以在声明的编译时计算编译时,假设下面的伪代码:

代码语言:javascript
复制
f(x)   = g(x)
g(x)   = x + h(x,x)
h(x,y) = x + y

由于每个值都是在编译时已知的,所以编译器可以将上面的内容重写为下面的等价物:

代码语言:javascript
复制
f(x) = x + x + x

换句话说,每个函数调用都已被删除,并替换为表达式本身的调用。同样适用的是一种名为回忆录的方法,其中传递的计算表达式的结果被存储起来,所以您只需要做一次艰苦的工作。

如果你知道g(5) = 15,为什么还要再计算一次?相反,每次需要时,只需将g(5)替换为15,这是可能的,因为声明为constexpr的函数不允许有副作用。

运行时

在运行时,这种情况不会发生(因为我们没有告诉代码这样做)。运行代码的小家伙需要从f跳到gh,然后从h跳回g,然后从g跳到f,同时存储每个函数的返回值并将其传递给下一个函数。

即使这家伙很小,而且他不需要跳得很远,他仍然不喜欢一直跳来跳去,他需要很长时间才能做到这一点,这需要时间。

但是在操作系统示例中,它真的计算了编译时间吗?

是的,对于那些不相信编译器确实计算了这一点并将其作为常量放在完成的二进制文件中的人,我将从下面的操作系统代码(g++ -S -Wall -pedantic -fconstexpr-depth=1000000 -std=c++11的输出)中提供相关的汇编指令。

代码语言:javascript
复制
main:
.LFB1200:
  .cfi_startproc
  pushq %rbp
  .cfi_def_cfa_offset 16
  .cfi_offset 6, -16
  movq  %rsp, %rbp
  .cfi_def_cfa_register 6
  subq  $16, %rsp
  movl  $131069, -4(%rbp)
  movl  $91, -8(%rbp)
  movl  $131069, %esi               # one of the values from constexpr
  movl  $_ZSt4cout, %edi
  call  _ZNSolsEj
  movl  $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
  movq  %rax, %rdi
  call  _ZNSolsEPFRSoS_E
  movl  $91, %esi                   # the other value from our constexpr
  movl  $_ZSt4cout, %edi
  call  _ZNSolsEi
  movl  $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
  movq  %rax, %rdi

  # ...
  # a lot of jumping is taking place down here
  # see the full output at http://codepad.org/Q8D7c41y
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16221716

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档