C 中的整数幂

Integer powers in C

在C代码中通常写成

a = b*b;

而不是

a = pow(b, 2.0);

对于 double 个变量。我明白了,因为 pow 是一个能够处理非整数指数的通用函数,所以人们应该天真地认为第一个版本更快。然而,我想知道编译器 (gcc) 是否将对 pow 的调用转换为具有整数指数的直接乘法作为任何可选优化的一部分。

假设不进行这种优化,手动写出乘法速度更快的最大整数指数是多少,如 b*b* ... *b

我知道我可以在给定的机器上进行性能测试以确定我是否应该关心,但我想更深入地了解 "the right thing" 应该做什么。

就正确的事情而言 - 考虑您的维护者而不仅仅是性能。我有一种预感,您正在寻找一般规则。如果您正在做一个简单且一致的数字平方或立方,我不会对这些使用 pow。 pow 很可能会进行某种形式的子例程调用而不是执行寄存器操作(这就是 Martin 指出体系结构依赖性的原因)。

您想要的是 -ffinite-math-only -ffast-math,可能 #include <tgmath.h> 这与 -Ofast 相同,无需强制执行 -O3 优化。

它不仅在启用 -ffinite-math-only and -ffast-math 时有助于这些类型的优化,当您忘记将正确的后缀附加到(非双精度)数学函数时,泛型数学类型也有助于弥补。

例如:

#include <tgmath.h>
float pow4(float f){return pow(f,4.0f);}
//compiles to
pow4:
    vmulss  xmm0, xmm0, xmm0
    vmulss  xmm0, xmm0, xmm0
    ret

对于 clang 这适用于最大 32 的幂,而 gcc 对至少 2,147,483,647 的幂(据我检查)这样做,除非启用 -Os(因为 jmp pow 函数在技术上更小) - 使用 -Os,它只会做 2 的幂。

警告 -ffast-math 只是其他几个优化的方便别名,其中许多优化打破了各种标准。如果您只想使用最少的标志来获得所需的行为,那么您可以使用 -fno-math-errno -funsafe-math-optimizations -ffinite-math-only