Will the compiler optimize division into multiplication
取决于这个问题浮点除法与浮点乘法。 由于某些原因,除法比乘法慢。
如果可能的话,编译器通常会用乘法代替除法吗?
例如:
1 2 3
| float a;
// During runtime a=5.4f
float b = a/10.f; |
那将会:
1 2 3
| float a;
// During runtime a=5.4f
float b = a*0.1f; |
如果它被认为是编译器可靠的问题,我使用VS2013默认编译器。 但是,如果我得到一个通用的答案(这个优化的理论有效性)会很好
-
编译器不能进行除法以便能够乘以倒数吗?
-
在"如果可能"的情况下不包括这种情况,除非接受准确性的损失,否则这是不可能的。 所以,希望只有在使用专门允许它的标志进行编译时。
-
@NathanOliver编译时间一个..不会受伤
-
goo.gl/AV8MlT看起来编译器在这里不会优化。
-
您可以使用fp:fast选项查看MSVC ++中的程序集输出:msdn.microsoft.com/en-us/library/e7s85ffb.aspx
-
我知道这是针对VS2013的,但是为了GCC用户的兴趣:在GCC中,专门启用此特定优化的标志是-freciprocal-math,当选择-funsafe-math-optimizations,-ffast-math或-Ofast时也会自动启用。 见gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/Optimize-Options.html
不,编译器不允许对一般情况执行此操作:由于倒数的表示错误,这两个操作可能产生不相同的结果。
在您的示例中,0.1没有精确表示为float。 这会导致乘以0.1并除以10的结果不同:
1 2 3 4
| float f = 21736517;
float a = f / 10.f;
float b = f * 0.1f;
cout << (a == b) << endl; // Prints zero |
演示。
注意:正如njuffa在下面的注释中正确指出的那样,有些情况下编译器可以对一组广泛的数字进行一些优化,如本文所述。 例如,乘以或除以2的幂相当于加入IEEE-754 float表示的指数部分。
-
虽然如果你告诉它你不关心编译器将进行转换(gcc的-ffast-math,无论MSVC的等价物是什么)。
-
鉴于C ++如何不精确地定义浮点数,我认为你错了。允许编译器执行此操作。然而,他们中的大多数人似乎选择不这样做(宁愿以速度为代价提供更高的准确性)。
-
必须分离出一种情况,即浮点除法可以很容易地用乘法替换,同时保持位相同的结果。对于具有IEEE-754算术的平台,对于2的幂的常数除数,当反向可表示时,这是正确的。我已经看到编译器应用这种优化(例如,除以2.0与0.5相乘)。如本文所述,有一种技术适用于更广泛的其他常数除数。可悲的是,我还没有看到任何编译器使用它。
-
@njuffa非常感谢您的好评!
-
@njuffa如果我是一个尽职尽责的编译器作者,当x / C保持有限时,我仍然会担心x * C1向上舍入到+inf,以及其他极端情况。它们可以通过将x_float / C_float替换为(float)((double) x_float * double_C1)来开始,这在许多目标体系结构上更快,不需要FMA,也没有编译器当前使用。
-
@PascalCuoq我已经使用了论文中的技术(请注意,我发布了草稿/预印本的链接,因为已发表的论文是我所知道的最好的报告)作为手动优化,并且不记得遇到任何问题。您可能已经意识到,混合浮点和双精度计算存在实际问题(许多GPU的吞吐量差别很大,SIMD矢量化障碍)。就FMA的使用而言:对此操作的支持正在迅速普及(GPU,x86,Power,SPARC,ARM),当然任何具有前瞻性的研究或编译器工作都应该假设它可用(恕我直言)
-
@njuffa要说清楚,你在谈论用fmaf(-0x1.3da6a4p-22f, x, x * 0x1.042974p+3f)替换单精度除法x / 0x1.f7cf3p-4f,对吧?
-
@PascalCuoq用fmaf (0x1.042974p+3f, x, -0x1.3da6a4p-22f * x)代替x / 0x1.f7cf3p-4f我觉得你的意思是什么?如果是的话,是的。我可以看到它分解为x = + / - INF和|x| <= 0x1.f1eb78p-108f。我之前使用它作为手动优化的地方既不会发生很大也不会很小的操作数,所以没有问题。在编译器中使用此技术作为一般解决方案将需要范围分析或快速路径/慢速路径方法,这可能是不切实际的
-
@njuffa抱歉,我错误地记住了这项技术,但是,当C1和C2有不同的符号时,无限性会导致问题。
-
我当然很欣赏采用这种技术作为通用解决方案的难度(当预计算倒数的头部和尾部具有相反的符号时,以及当被除数小到导致商的尾部计算中的下溢时,会出现明显的问题。 )。要清楚,我只是指保证按位相同结果的转换,因此是"安全的"。已经有很多编译器优化选项适用于那些不介意偶然出现错误结果的人:-)