【问题标题】:Is fmod faster than % for integer modulus calculation整数模数计算的 fmod 比 % 快吗
【发布时间】:2017-05-31 19:15:07
【问题描述】:

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

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

其中matrixint 的数组,nsize_t

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

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

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

【问题讨论】:

  • fmod 正在使用浮点值,这些值将被转换为 double 并返回。所以:没有。对于整数运算,请使用% 运算符。
  • 可能会慢一些吗?我不习惯从 C 语句中生成相应的程序集,但我想如果你使用 fmod 而不是 %

标签: c integer modulus


【解决方案1】:

在实验上(并且完全违反直觉),fmod% 快 - 至少在具有 6400 bogomips 的 AMD Phenom(tm) II X4 955 上。下面是两个使用这两种技术的程序,它们都使用相同的编译器 (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 秒。

【讨论】:

  • 现在这很有趣 - 很好,我应该自己做的。我很高兴我提出了这个问题并得到了如此聪明的回应。
  • 在我的系统上,版本 1 运行时间为 3.07 秒,版本 2 运行时间为 8.97 秒。所以我得到了相反的结果,有更大的余量。这在很大程度上取决于您使用的确切硬件,以及其他各种因素。
  • @DietrichEpp 出于好奇,您使用的是什么 CPU?我想我的 CPU 很慢,但 FPU 似乎还可以:)
  • 这不是完全意外,您的循环代码使用整数运算,这意味着% 浮点执行单元坐在那里什么都不做,循环增量正在等待为整数除法。对于fmod,循环增量和取模使用不同的资源并同时发生。但这对于围绕模数和 CPU 子体系结构的代码来说都是极其具体的,不应该用于做出一般性陈述,例如问题所要求的陈述。另一个 CPU 有足够的整数执行单元来执行整数除法和循环更新
  • 这是一个 i5-4258U。尽管 idiv 的速度非常慢,但在优化处理器的整数和浮点部分所付出的相对努力在不同处理器之间存在很大差异。
【解决方案2】:

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

fmod 在具有高延迟 IDIV 指令的架构上可能会快一些,这需要(比如说)大约 50 个周期或更多,因此 fmod 的函数调用和 int &lt;---&gt; doubleconversions 成本可以是摊销。

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 对于我的特定场景 n > 0 并且通常
    猜你喜欢
    • 2023-03-14
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多