在 C++ 中做乘法比提高到 2 次方更有效吗?
我正在尝试进行最终的详细优化。编译器会将 x*x 视为与 pow(x,2) 相同吗?如果我没记错的话,由于某种原因,乘法更好,但在 c++11 中可能无关紧要。
谢谢
如果您将乘法与pow()
标准库函数进行比较,那么是的,乘法肯定更快。
我一般来说,除非您有证据表明存在热点,否则您不应该担心这样的 pico 优化(即,除非您已经在现实场景下分析了您的代码并确定了特定的代码块。另外请记住,您的聪明技巧实际上可能会导致您的假设不再成立的新处理器中的性能回归。
算法更改是您在计算成本上获得最大收益的地方。专注于此。
修补乘法并做一些聪明的比特黑客......嗯,那里没有那么多爆炸*因为当前一代的优化编译器在他们的工作中真的非常出色。这并不是说他们不能被击败。他们可以,但不容易,可能只有像 Agner Fog 这样的少数人。
* 当然也有例外。
在性能方面,请始终进行测量以支持您的假设。永远不要相信理论,除非你有一个可以证明理论正确的基准。
另外,请记住,在 C++ 中不会x ^ 2
产生2 的平方:
#include <iostream>
int main()
{
int x = 4;
std::cout << (x ^ 2); // Prints 6
}
pow() 的实现通常涉及对数、乘法和指数,因此它肯定会比简单的乘法花费更长的时间。大多数现代高端处理器可以在几个时钟周期内对整数值进行乘法运算,而对浮点乘法运算则需要十几个周期。求幂可以作为需要几十个或更多周期的复杂(微编码)指令完成,也可以作为一系列乘法和加法(通常使用交替的正数和负数,但不确定)来完成。求幂是一个类似的过程。
在较低范围的处理器(例如 ARM 或更早的 x86 处理器)上,结果甚至更糟。在一个浮点运算中数百个周期,或者在某些处理器中,甚至浮点计算也是许多整数运算,它们执行与更高级处理器上的浮点指令相同的步骤,因此所花费的时间pow()
可能是数千个周期,相比之下到十几个左右进行乘法。
无论使用哪种选择,整个计算都将比简单的乘法长得多。
当指数很大或不是整数时,该pow()
函数很有用。即使是比较大的指数,也可以通过多次平方或立方来计算,速度会比pow()
.
当然,有时编译器可能能够弄清楚您想要做什么,并将其作为一个乘法序列来作为优化。但我不会依赖它。
最后,像往常一样,对于性能问题:如果它对你的代码真的很重要,那么测量它——你的编译器可能比你瘦的更聪明。如果性能不重要,则执行使代码最易读的计算。
pow
是库函数,而不是运算符。除非编译器能够优化调用(它通过利用其对标准库函数行为的了解而合法地做到这一点),否则调用pow()
将强加函数调用的开销以及pow()
函数必须执行的所有额外内容做。
的第二个参数pow()
不必是整数;例如pow(x, 1.0/3.0)
会给你一个立方根的近似值x
。这将需要一些相当复杂的计算。如果第二个参数是一个小的整数值,它可能会退回到重复乘法,但是它必须在运行时检查它。
如果您要平方的数字是整数,pow
则需要将其转换为double
,然后将结果转换回整数类型,这相对昂贵并且可能导致细微的舍入错误。
使用x * x
很可能比 更快、更可靠pow(x, 2)
,而且更简单。(在大多数情况下,简单性和可靠性是比速度更重要的考虑因素。)
你应该看看 boost.math 的 pow 函数模板。它将指数作为模板参数并自动计算,例如,pow<4>(x) 为 (x*x)*(x*x)。
您应该阅读以下链接 为什么 GCC 不将 a*a*a*a*a*a 优化为 (a*a*a)*(a*a*a)?
pow(x,2) 很可能会转换为 x x。然而,诸如 pow(x,4) 之类的更高功率可能不会尽可能优化。例如 pow(x,4) 可以在 3 次乘法 x x x x 或两次 (x x) (x*x) 中完成,具体取决于您对浮点定义的要求有多严格(默认情况下,我认为它将使用3次乘法。
看看 pow(x*x,2) 在有和没有 -ffast-math 的情况下会产生什么会很有趣。
C/C++ 没有原生的“power”运算符。^
是按位异或 (xor)。因此,该pow
功能可能是您正在寻找的。
实际上,对整数求平方x*x
是最直接的方法,如果可用,某些编译器可能会将其优化为机器操作。