对于整数模计算,fmod 是否比 % 快

Is fmod faster than % for integer modulus calculation

刚在一些旧的 src 代码中找到以下行:

int e = (int)fmod(matrix[i], n);

其中matrixint的数组,nsize_t

我想知道为什么在我们有整数参数的地方使用 fmod 而不是 %,即为什么不使用:

int e = (matrix[i]) % n;

选择 fmod 而不是 % 可能是出于性能原因,还是只是一段奇怪的代码?

实验上(相当 counter-intuitively),fmod% 快 - 至少在 AMD Phenom(tm) II X4 955 with 6400 bogomips。下面是两个使用其中任何一种技术的程序,它们都使用相同的编译器 (GCC) 和相同的选项 (cc -O3 foo.c -lm) 编译,并且 运行 在相同的硬件上:

#include <math.h>
#include <stdio.h>

int main()
{
    int volatile a=10,b=12;
    int i, sum = 0;
    for (i = 0; i < 1000000000; i++)
        sum += a % b;
    printf("%d\n", sum);
    return 0;
}

运行 时间:9.07 秒

#include <math.h>
#include <stdio.h>

int main()
{
    int volatile a=10,b=12;
    int i, sum = 0;
    for (i = 0; i < 1000000000; i++)
        sum += (int)fmod(a, b);
    printf("%d\n", sum);
    return 0;
}

运行 时间:8.04 秒

Could there possibly be a performance reason for choosing fmod over % or is it just a strange bit of code?

fmod 在具有 high-latency IDIV 指令的架构上可能会快一点,这需要(比如说)~50 个周期或更多,所以 fmod函数调用和 int <---> double 转化成本可以摊销。

根据 Agner's Fog instruction tablesIDIV 在 AMD K10 架构上需要 24-55 个周期。与现代 Intel Haswell 相比,其延迟范围为 22-29 个周期,但如果没有依赖链,Intel 上的倒数吞吐量要好得多,为 8-11 个时钟周期。

fmod 可能比选定架构上的整数除法快一点点。

但是请注意,如果 n 在编译时具有已知的非零值,则 matrix[i] % n 将被编译为乘法并进行小的调整,这应该比整数模运算快得多和浮点模数。

另一个有趣的区别是 n == 0INT_MIN % -1 上的行为。整数模运算会在溢出时调用未定义的行为,这会导致许多当前体系结构上的程序异常终止。相反,浮点模数没有这些边界情况,结果是 +Infinity-InfinityNan 取决于 matrix[i]-INT_MIN 的值,全部超出 int 的范围并且转换回 int 是实现定义的,但通常不会导致程序异常终止。这可能是最初的程序员选择这个令人惊讶的解决方案的原因。