为什么在我的电脑上没有g++中的-O2,sqrt会变得更快

Why sqrt become much faster without -O2 in g++ on my computer?

本文关键字:sqrt -O2 中的 电脑 我的 g++ 为什么      更新时间:2023-10-16

考虑以下代码:

#include <cstdio>
#include <cmath>
const int COUNT = 1000000000;
int main()
{
    double sum = 0;
    for (int i = 1; i <= COUNT; ++i) {
        sum += sqrt(i);
    }
    printf("%fn", sum);
    return 0;
}

没有-O2,它在我的计算机上只运行2.9秒,而有-O2时它运行6.4秒。

我的电脑是Fedora 23,g++5.3.1。

我在Ubuntu 14.04(g++4.8)上也尝试过同样的方法,它没有问题(都是6.4秒)。

Naive版本使用对glibc sqrt函数的调用。

优化版本使用SSE sqrtsd指令。但在指令完成后,它会检查结果值是否不是NaN。如果结果值是NaN,那么它会调用glibc sqrt函数来设置正确的错误标志(请参阅math_error(7)的手册页)。有关详细解释,请参阅编译器为什么在编译的汇编代码中生成额外的sqrt。

为什么gcc认为这更快?没人知道。如果您确信您的数字不会生成NaN,请使用-fno-math-errno编译选项。

调查程序集可能会找到一些答案,但查看代码差异的最简单方法是执行-fdump-tree-optimized。这个问题似乎与sqrt过载有关,即由C库sqrt(double)和C++11sqrt(int)提供的过载。后者似乎更快,GCC似乎不在乎您是否使用-std=c++11或前缀std::sqrt

以下是带有-O2-O的转储摘录(没有编号的-O启用优化,要禁用所有优化,请省略-O):

  int i;
  double sum;
  double _9;
  __type _10;
  <bb 2>:
  <bb 3>:
  # sum_15 = PHI <sum_6(3), 0.0(2)>
  # i_16 = PHI <i_7(3), 1(2)>
  _9 = (double) i_16;
  _10 = __builtin_sqrt (_9);
  sum_6 = _10 + sum_15;
  i_7 = i_16 + 1;
  if (i_7 == 1000000001)
    goto <bb 4>;
  else
    goto <bb 3>;

则无-O2:

  <bb 4>:
  _8 = std::sqrt<int> (i_2);
  sum_9 = sum_1 + _8; 
  i_10 = i_2 + 1; 
  goto <bb 3>; 

请注意,它使用std::sqrt<int>。对于持怀疑态度的人,请参阅为什么全球范围内的sqrt比MinGW中的std::sqrt慢得多?