编译器会将除法优化为乘法

Hum*_*awi 19 c++ floating-point compiler-optimization c++11

取决于这个问题浮点除法与浮点乘法.由于某些原因,除法比乘法慢.

如果可能的话,编译器通常会用乘法代替除法吗?

例如:

float a;
// During runtime a=5.4f
float b = a/10.f;
Run Code Online (Sandbox Code Playgroud)

那将会:

float a;
// During runtime a=5.4f
float b = a*0.1f;
Run Code Online (Sandbox Code Playgroud)

如果它被认为是编译器可靠的问题,我使用VS2013默认编译器.但是,如果我得到一个通用的答案(这个优化的理论有效性)会很好

das*_*ght 20

不,编译器不允许对一般情况执行此操作:由于倒数的表示错误,这两个操作可能产生不相同的结果.

在您的示例中,0.1没有精确的表示形式float.这导致乘以0.1和除以的结果10不同:

float f = 21736517;
float a = f / 10.f;
float b = f * 0.1f;
cout << (a == b) << endl; // Prints zero
Run Code Online (Sandbox Code Playgroud)

演示.

注意:正如njuffa在下面的注释中正确指出的那样,有些情况下编译器可以对一组广泛的数字进行一些优化,如本文所述.例如,乘以或除以2的幂等于加入IEEE-754 float表示的指数部分.

  • 虽然编译器会进行转换,如果你告诉它你不关心(gcc的`-ffast-math`,无论MSVC的等价物是什么). (5认同)
  • 必须分离浮点除法可以很容易地用乘法*替换的情况,同时保持位相同的结果*.对于具有IEEE-754算术的平台,对于2的幂的常数除数,当反向可表示时,这是正确的.我见过编译器应用这种优化(例如,除以2.0乘以0.5).有一种技术适用于更广泛的其他常数除数,如[本文](http://perso.ens-lyon.fr/nicolas.brisebarre/Publi/fpdivision.pdf)所述.可悲的是,我还没有看到任何编译器使用它. (4认同)
  • 我当然很欣赏采用这种技术作为通用解决方案的难度(当预计算倒数的头部和尾部具有相反的符号时,当被除数很小时会导致商数的尾部计算中出现下溢时,会出现明显的问题. ).要清楚,我只是指保证按位相同结果的转换,因此是"安全的".已经有很多编译器优化选项适用于那些不介意偶然出现错误结果的人:-) (2认同)