c++编译器对非交换运算的优化程度
Extent of G++ compiler optimization on non-commutative operations
我很关心g++优化器对算术运算的影响,特别是不一定可以交换的整数运算,例如eg *和/。当我在gdb中查看一个使用-O3标志编译的简单函数时,这个问题就出现了;总的来说,它是一个更好的函数,但它的形式与之前完全不同,没有优化,操作被删除了,有些被重新安置了。下面是一个简单的函数,我将用它来演示我所关心的关键问题;
int ClipLower(int num, int dig){
int Mult10 = 1;
while (dig != 0){
Mult10 *= 10, dig--;
}
return ((num / Mult10) * Mult10);
}
这个函数只是截断数字'dig'下面的base10位。我担心的是,编译器是否会考虑整数上的数学是不可交换的?那么,编译器是否会尝试将(num/mult10) * mult10减少为num * 1,当然会丢弃其中一个?
我知道volatile将避免这种情况,但我仍然希望我的代码尽可能优化。所以从本质上讲,我想问gnu优化器是否会理解整数数学是非交流的,进一步说,优化出错到底有多重要。
<标题> 也这是函数在-O4处的反汇编,正如您所看到的,操作顺序很好
13 return ((num / Mult10) * Mult10);
cltd
idiv %ecx
imul %ecx,%eax
ret
有趣的是,编译器在函数之后生成了一个无操作的负载,可能是作为填充,因为它最终非常小。
标题>下面是g++中-O3
对应的标志列表:https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
现在如果你仔细看,还有-Ofast
它被定义为-O3
+一些其他的,特别是-ffast-math
。在-ffast-math
的描述中,您可以阅读:
此选项不能被除-Ofast之外的任何-O选项打开,因为对于依赖于IEEE或ISO规则/数学函数规范的精确实现的程序,它可能导致错误的输出。然而,对于不需要这些规范保证的程序,它可能产生更快的代码。
这样做是为了确保默认的编译器标志不违反舍入错误和其他浮点标准规范。
在SO上也有一个相关的问题,为什么编译器不把a*a*a*a*a*a
优化到(a*a*a)^2
,答案是一样的。(I cannot find the link atm =/)
顺便说一句,Mult10 *= 10, dig--;
你想失去遵循你的代码的人吗?= D
EDIT:另一个顺便说一下,通过-O3
没有效果。除了有人说你可能会溢出一些内部变量。我没有测试溢出,但我确信-O4
和-O100
在写这篇文章的时候相当于-O3
。
试一下,看看程序集
优化不应该影响输出,只影响速度。应保持舍入。但是bug还是会发生的,尽管现在已经很少了。
通常问题更可能出现在浮点数上。2/7与float
s可能略有不同。
对于int
s,无论进行什么优化,它都应该始终为0,即使它乘以7。
- 空基优化子对象的地址
- 关闭||运算符优化
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 为什么开关的优化方式与 c/c++ 中的链接不同?
- 线性优化目标函数中的绝对值
- GCC 会优化内联访问器吗?
- gcc 如何优化此循环?
- 如何防止 CUDA-GDB 中的<优化输出>值
- 为什么我的程序在 O0 和 O2 的优化级别返回不同的结果
- gcc 是否以代数方式优化 c++ 代码,如果是,在多大程度上优化
- c++编译器对非交换运算的优化程度