在gcc-4.8中预先计算(C++ 11)

mas*_*oud 23 c++ gcc c++11

在旧测试代码gcc-4.4.0gcc-4.6.4,编译器能够应用智能优化和预计算的结果const输入:

#include <iostream>
#include <chrono>
using namespace std;

const auto N = 1000000000ULL;  // constexptr is tested, no effect

unsigned long long s(unsigned long long n)
{
    auto s = 0ULL;
    for (auto i = 0ULL; i < n; i++)
        s += i;
    return s;
}

int main()
{
    auto t1 = std::chrono::high_resolution_clock::now();

    auto x = s(N);

    auto t2 = std::chrono::high_resolution_clock::now();
    auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(t2-t1).count();
    cout << "Result: " << x << " -- time (ms):" << t/0.1e7 << endl;
}
Run Code Online (Sandbox Code Playgroud)

N是一个常量值,然后编译器可以s在编译时运行函数并将结果赋值给x.(不需要运行时计算N)

结果在不同版本的gcc(以及一个版本的clang):

  • 最后一个版本(铛-3.4)的结果(预先计算)0.001532 ms.
  • 旧版本(GCC-4.4.0)结果(计算预)0.013517 ms.
  • 旧版本(GCC-4.6.4)结果(计算预)0.001 ms.
  • 较新的版本(gcc-4.8.0 +)不会在编译时计算它,结果:1313.78 ms!!.

题:

  • 4.8.1中是否省略了此优化?为什么?
  • 是否有任何编译器命令/开关启用它(如果它默认禁用)?
  • 如果省略,我如何强制编译器进行预先计算?

 


注意(1):我测试了两个-O2-O3切换,没有效果.

注意(2):强制,我指的是编译器的命令和开关.

注(3):函数s只是一个例子,可以用更复杂的函数代替.

mas*_*oud 13

我已将其作为错误提交.是的,它是版本4.8中的回归,已在5周前的较新版本中修复.在这里关注它:


Ben*_*igt 7

您可以使用新的C++ 11 constexpr关键字强制它在编译时运行.

首先,您必须将迭代转换为递归(此要求在C++ 1y中删除),例如:

constexpr unsigned long long s(unsigned long long n)
{
    return n? n + s(n-1): 0;
}
Run Code Online (Sandbox Code Playgroud)

或者使用尾递归(当输入变量时,仍适用于运行时计算):

constexpr unsigned long long s_impl( unsigned long long accum, unsigned long long n, unsigned long long n_max )
{
    return (n < n_max)? s_impl(accum + n + 1, n + 1, n_max): accum;
}
constexpr unsigned long long s(unsigned long long n)
{
    return s_impl(0, 0, n);
}
Run Code Online (Sandbox Code Playgroud)

(在C++ 1y中,您需要做的就是将constexpr关键字添加到现有实现中)

然后用它调用它

constexpr auto x = s(N);
Run Code Online (Sandbox Code Playgroud)