【问题标题】:Arithmetic operations and the compiler optimizations算术运算和编译器优化
【发布时间】:2012-10-05 05:57:43
【问题描述】:

我正在考虑一个定点算术库,为了决定库本身(通过表达式模板)应该完成多少优化,我开始质疑优化器已经完成了多少。举个例子:

//This is a totally useless function to exemplify my point
void Compare(FixedPoint a, FixedPoint b) {
   if(a/b>10) {
      ... do stuff
   }
}

现在,在这个函数中,FixedPoint 类的典型实现将导致

if( ( (a_<<N) / b_) > (10 <<N) ) {
... do stuff
}

其中N 是小数位数。该表达式可以在数学上转换为:

(a_ > 10*b_)

即使当您考虑整数溢出时,这种转换不会导致相同的行为。我的库的用户可能会关心数学等价性,并且更愿意使用简化版本(可能通过表达式模板提供)。

现在的问题是:优化器是否敢自己进行优化,即使行为并不严格相同?我应该为这样的优化而烦恼吗?请注意,此类优化并非微不足道。实际上,如果您确实进行了这些优化,那么在使用定点算术时,您很少需要进行任何位移。

【问题讨论】:

  • 简单规则:如果编译器不能向自己证明行为不会改变,那么它就不会优化。
  • 此外,您已经提出了一个不匹配的示例。 (溢出)它本身已经禁止编译器进行这种优化。也就是说,编译器可能会执行其他技巧(例如提升为更大的类型)。但是快速测试表明VS2010没有做这个优化。
  • @Mystical 没有 c 标准,除了程序员避免溢出,因此允许优化忽略溢出。 (我认为这里有一个关于 SO 的问题是循环不会终止,因为终止条件依赖于溢出(如果我没记错的话,与 for(int i=0;i&gt;=0;i++); 类似)。但是我对此并不完全确定。
  • @ted 真是巧合! That question你指的是我问的。 :) 在这种情况下,如果10*b_ 结束,优化将引入溢出。所以即使a/b 没有溢出,10*b_ 也可以。所以编译器不能在不提升到更大类型的情况下做到这一点。
  • @Mystical:谢谢你,幸运的是我现在从你的问题中学到了更多。

标签: c++ c optimization arithmetic-expressions


【解决方案1】:

这将取决于 a_b_ 类型是有符号还是无符号。

在 C 和 C++ 中,有符号溢出在技术上是未定义的行为,而无符号溢出是使用二补码算法完成的。

尽管如此,一些编译器拒绝优化该代码,因为许多程序依赖于有符号溢出的二补码行为。

优秀的现代编译器将有一个选项来启用/禁用这个特定的假设:有符号整数不会溢出。默认的选项会因编译器而异。

以 GCC 为例,请参阅选项 -fstrict-overflow/-fno-strict-overflow 和相关警告 -Wstrict-overflow

【讨论】:

  • 谢谢你的回答,我想我最好还是通过表达式模板来做这样的优化。
  • 这也取决于它们是否大于或小于int。无论上下文如何,小于int 的无符号值都会被提升为有符号值,即使在计算的高位永远不会对结果产生任何已定义影响的情况下,这也可能导致未定义行为。
猜你喜欢
  • 2018-08-19
  • 1970-01-01
  • 2014-05-24
  • 2016-09-11
  • 2020-01-09
  • 1970-01-01
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多