计算余数不是一条指令
Clang C 编译器为模计算生成了以下代码:
udiv x10, x0, x9
msub x10, x10, x9, x0
好消息,这并不慢!
虽然 x86 在一条指令中执行此操作,但这并不能使其更快。
在 Apple M-1 上,上述指令对的执行时间与单个步骤大致相同。这可能是由于instruction macro-fusion 将多条指令解码为单个 µ-op。这也可能是由于多个execution units 的并行性。可能在一个 EU 中完成,除法计算的余数被缓存并立即返回。
无论实现什么,它似乎都和英特尔的单指令形式一样快。
仅限分区
时间:
$ time ./a.out 12345678901
Total: 301123495054
real 0m10.036s
user 0m9.668s
sys 0m0.031s
指令生成:
udiv x10, x0, x9
仅剩余
时间:
$ time ./a.out 12345678901
Total: 8612082846779832640
real 0m10.190s
user 0m9.768s
sys 0m0.070s
生成的指令:
udiv x10, x0, x9
msub x10, x10, x9, x0
除法和余数
时间:
$ time ./a.out 12345678901
Total: 8612083123211969892
real 0m10.103s
user 0m9.752s
sys 0m0.019s
生成的指令:
udiv x10, x0, x9
msub x11, x10, x9, x0
基准代码
以下 C 代码可以在 q = n / d 或 r = n % d 注释掉的情况下运行:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
unsigned long long n, d, q=1, r=1, total=0;
n = strtoull(argv[1], NULL, 10);
total = 0;
for (d=1 ; d<=n ; d++) {
q = n / d;
r = n % d;
total += q + r;
}
printf("Total: %llu", total);
return 0;
}