是否有任何C++编译器能够优化 lround(pow(sqrt(i), 2)) 现在或不久的将来用 i 替换它

Is any C++ compiler able to optimize lround(pow(sqrt(i), 2)) replacing it with i, now or in the near future?

本文关键字:替换 将来 优化 编译器 lround 任何 是否 sqrt pow C++      更新时间:2023-10-16

在某些微基准测试的情况下,静态代码分析器足够智能,可以消除具有相同参数值的多个函数调用,从而使测量变得无用。基准测试函数f如下代码:

long s = 0;
...
for (int i = 0; i < N; ++i) {
  startTimer();
  s += f(M);
  stopTimer();
}
...
cout << s;

可以被优化器击败。我想知道,当前或不久的将来优化器技术是否足够聪明来击败这个版本:

long s = 0;
...
for (int i = 0; i < N; ++i) {
  long m = lround(pow(sqrt(i), 2))/i*M;
  startTimer();
  s += f(m);
  stopTimer();
}
...
cout << s;

回答你的标题问题:

是否有任何C++编译器能够优化lround(pow(sqrt(i),2))现在或不久的将来用i替换它?

是的,对于静态已知的参数:在Godbolt上直播

该示例程序中的所有代码都编译为单个常量值!而且,最重要的是,这是禁用优化的:g++-4.8 -O0 :)

#include <cmath>
constexpr int N = 100;
constexpr double M = 1.0;
constexpr int i = 4;
static constexpr double foo1(int i) { return sqrt(i); }
static constexpr auto f1 = foo1(4);
static constexpr double foo2(int i) { return pow(sqrt(i), 2); }
static constexpr auto f2 = foo2(4);
static constexpr double foo3(int i) { return pow(sqrt(i), 2)/i*M; }
static constexpr auto f3 = foo3(4);
static constexpr long foo4(int i) { return pow(sqrt(i), 2)/i*M; }
static constexpr auto f4 = foo4(4);
#include <cstdio>
int main()
{
    printf("f1 + f2 + f3 + f4: %fn", f1 + f2 + f2 + f3);
}

Get 编译成一个静态已知的常量:

.LC1:
    .string "f1 + f2 + f3 + f4: %fn"
    .text
    .globl  main
    .type   main, @function
main:
.LFB225:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movabsq $4622382067542392832, %rax
    vmovd   %rax, %xmm0
    movl    $.LC1, %edi
    movl    $1, %eax
    call    printf
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret

瞧。这是因为 GNU 标准库在 C++11 模式下有 constexpr 个版本的数学函数(lround 除外)。

完全可以想象编译器展开一个循环,例如

for (int i; i<5; ++i) 
    s += foo(i);

s += foo(1);
s += foo(2);
s += foo(3);
s += foo(4);

虽然我还没有检查过。

这是可能的,但必须向优化器传授库函数的语义,这既困难又耗时。

再说一次IEEE754数学是棘手的。

声明volatile long m= M;呢?