对于整数模计算,fmod 是否比 % 快
Is fmod faster than % for integer modulus calculation
刚在一些旧的 src 代码中找到以下行:
int e = (int)fmod(matrix[i], n);
其中matrix
是int
的数组,n
是size_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 tables,IDIV
在 AMD K10 架构上需要 24-55 个周期。与现代 Intel Haswell 相比,其延迟范围为 22-29 个周期,但如果没有依赖链,Intel 上的倒数吞吐量要好得多,为 8-11 个时钟周期。
fmod
可能比选定架构上的整数除法快一点点。
但是请注意,如果 n
在编译时具有已知的非零值,则 matrix[i] % n
将被编译为乘法并进行小的调整,这应该比整数模运算快得多和浮点模数。
另一个有趣的区别是 n == 0
和 INT_MIN % -1
上的行为。整数模运算会在溢出时调用未定义的行为,这会导致许多当前体系结构上的程序异常终止。相反,浮点模数没有这些边界情况,结果是 +Infinity
、-Infinity
、Nan
取决于 matrix[i]
和 -INT_MIN
的值,全部超出 int
的范围并且转换回 int
是实现定义的,但通常不会导致程序异常终止。这可能是最初的程序员选择这个令人惊讶的解决方案的原因。
刚在一些旧的 src 代码中找到以下行:
int e = (int)fmod(matrix[i], n);
其中matrix
是int
的数组,n
是size_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 tables,IDIV
在 AMD K10 架构上需要 24-55 个周期。与现代 Intel Haswell 相比,其延迟范围为 22-29 个周期,但如果没有依赖链,Intel 上的倒数吞吐量要好得多,为 8-11 个时钟周期。
fmod
可能比选定架构上的整数除法快一点点。
但是请注意,如果 n
在编译时具有已知的非零值,则 matrix[i] % n
将被编译为乘法并进行小的调整,这应该比整数模运算快得多和浮点模数。
另一个有趣的区别是 n == 0
和 INT_MIN % -1
上的行为。整数模运算会在溢出时调用未定义的行为,这会导致许多当前体系结构上的程序异常终止。相反,浮点模数没有这些边界情况,结果是 +Infinity
、-Infinity
、Nan
取决于 matrix[i]
和 -INT_MIN
的值,全部超出 int
的范围并且转换回 int
是实现定义的,但通常不会导致程序异常终止。这可能是最初的程序员选择这个令人惊讶的解决方案的原因。