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

C++ 是任何C++;编译器能够优化lrund(pow(sqrt(i),2))用i替换它,现在还是在不久的将来?,c++,optimization,C++,Optimization,在微基准标记的某些情况下,静态代码分析器足够聪明,可以省略具有相同参数值的多个函数调用,从而使测量变得无用。标杆功能f,代码如下: long s = 0; ... for (int i = 0; i < N; ++i) { startTimer(); s += f(M); stopTimer(); } ... cout << s; long s=0; ... 对于(int i=0;i是任何一个C++编译器能够优化LnEnter(PoW(Sqt(i),2)),用现在

在微基准标记的某些情况下,静态代码分析器足够聪明,可以省略具有相同参数值的多个函数调用,从而使测量变得无用。标杆功能
f
,代码如下:

long s = 0;
...
for (int i = 0; i < N; ++i) {
  startTimer();
  s += f(M);
  stopTimer();
}
...
cout << s;
long s=0;
...
对于(int i=0;icout这是可能的,但必须向优化者传授库函数的语义,这既困难又耗时


然后,IEEE754的数学也很棘手。

声明
volatile long m=m取而代之?

回答您的标题问题:

< P>是任何一个C++编译器能够优化LnEnter(PoW(Sqt(i),2)),用现在或近期的I/P>替换它吗? 是的,对于静态已知参数:请参见

该示例程序中的所有代码都被编译为一个常量值!最重要的是,这是禁用了优化的情况下(
g++-4.8-O0
:)

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

完全可以想象编译器会像这样展开一个循环

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

尽管我还没有检查它。

“有”编译器吗?那么答案是否定的,因为根本没有优化,它仍然是C++(并且有这样的东西)。关于您的编译器,只需查看asm输出…为什么不使用一点algerbra?这不是不可想象的,编译器可以通过强大的代数系统得到增强。无论如何,如果出现这种情况,我更希望编译器告诉我它应用了什么转换。@YvesDaoust编译器确实会告诉您,只需查看程序集列表。不管怎样,其余的都在“好像”规则下,作为程序员,转换不应该与您有关。该标准不用于指定代码生成。它只定义生成代码的正确行为。不过,这里并没有说明时间。你们知道有任何现有的优化器进行这种分析吗?+1对于IEEE 754数学来说是很棘手的。优化器通常会忽略大部分FP表达式,因为许多“无害”的更改可能会产生微妙但重要的影响。我一下子记不起来了,有一些研究项目想要对库函数的语义进行推理,但它更多是为了代码分析而不是优化。研究人员提到它也可以用于优化器,但我忘记了它的名字。抱歉。@MatteoItalia优化器通常会忽略大部分FP表达式,这正是我所希望的。他们不敢冒险简化它:-)@Paul他们不需要简化任何东西来优化静态已知参数。他们可以在编译时执行一致性实现并插入结果,正如您在我的回答中已经看到的那样。我不知道这如何解决我的问题。你认为波动性长m=lrund(pow(sqrt(i),2))/i*m
使优化器更容易用
long m=m替换它?实现目标的更好方法是禁止优化函数调用。我知道了,调用
f(m)
,其中
m
volatile
。非常简单,谢谢。你的例子和我的用例不太一样<当
N
较大时,不能将code>constexpr
应用于循环内的表达式
lrund(pow(sqrt(i),2))/i*M
,因为它将始终用于基准测试。N是否较大无关紧要。编译器可以决定它可以预先计算整个shebang。
lround
是当前阻碍整个施工的因素。此外,我还详细说明了我回答的问题的哪一部分。我确实意识到还有更多的上下文,但我认为这本身就足以提供足够的信息,这让许多人感到惊讶:)好吧,您明确指示编译器在编译时使用
conexpr
来计算这些表达式。我确信对于N=1000000,编译器不会展开我的循环并计算1M表达式。说到这里,你的例子仍然显示了一个有趣的角度,谢谢。@ PululcZak的观点是“是的,任何C++编译器都能优化StasyType((PoW(Sqt(i),2))/i*m)替换它。而且,不,我实际上没有做太多特别的工作,GNU stdlib已经将
pow
sqrt
定义为constexpr。将简化代码以减少confusion@PaulJurczak我知道。我再重复一遍:我知道这些限制,我回答了问题的一个具体部分。我希望它能提供一些信息。(我只是指出,我并不是像你在之前的评论中所说的那样,为了这种行为而跳槽的)。干杯
#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: %f\n", f1 + f2 + f2 + f3);
}
.LC1:
    .string "f1 + f2 + f3 + f4: %f\n"
    .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
for (int i; i<5; ++i) 
    s += foo(i);
s += foo(1);
s += foo(2);
s += foo(3);
s += foo(4);