是否有任何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?
在某些微基准测试的情况下,静态代码分析器足够智能,可以消除具有相同参数值的多个函数调用,从而使测量变得无用。基准测试函数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;
呢?
相关文章:
- 模板参数替换失败,并且未完成隐式转换
- 如何用转义符替换字符串中的所有特殊字符
- 为什么除非添加括号,否则构造函数上的模板替换会失败?
- 在一个读写器队列中,我可以用volatile替换原子吗
- 用符号版本替换对函数的所有调用
- 如何通过替换顺序代码的while循环来添加OpenMP for循环
- 替换基于地图的所有引用
- 按平均值替换数组中的元素
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- 初始化 std::vector 替换为单大括号而不是双大括号
- 使用 std::async 时死锁,将来作为成员
- 删除/替换C++字符串中的多字符 (ÿû)
- 将 malloc 替换为数组
- 如何替换此示例代码片段中已弃用的handler_type_t或 boost::asio::handler_type?
- 如何在C++中用'\'替换''来处理转义序列?
- 替换密码:哪一个?
- 替换 C++17 中移除的绑定 1st
- 将 Boost MPL 容器替换为 C++17 功能
- 是否有任何C++编译器能够优化 lround(pow(sqrt(i), 2)) 现在或不久的将来用 i 替换它