哪个操作需要更多的CPU时钟周期,取模还是比较?

4

求模运算和比较运算,哪一个需要更多的 CPU 时钟?

这段代码会花费更多的时间吗:

for(j = i; j <= 10; j++)
{
   if(j == 10) printf("0");
   else printf("%d", j);
}

或者这个

for(j = i; j <= 10; j++)     
   printf("%d", j % 10);

为什么?

2
如果您想比较汇编代码,可以反汇编可执行文件(或使用gcc -S)并检查代码,还可以使用优化标志。 - Grijesh Chauhan
基本上是一样的,因为printf()函数会占用99%的时间。如果你清理掉它,@Javier的答案是正确的。 - Gangnus
3个回答

10

如果以CPU周期计算,取模运算可能需要更多的周期;这可能取决于CPU。然而,使用现代处理器来衡量性能不是很好的方法,因为这些处理器可以同时运行多个指令(流水线),拥有多层缓存等。在这种情况下,添加一个额外的测试将意味着增加一个分支,这可能在时间上更重要(即影响指令流水线)。唯一确定的方法是进行优化编译并计时。

我知道你的例子只是一个例子,但这也说明了“过早优化”的问题。调用printf的时间比取模或比较操作长得多。如果你想优化你的例子,你可以写成:

printf ("1234567890");

4
比较是一种简单的操作,通常会更快(CPU可以在位上使用逻辑运算符)。
如果对一个不是2的幂次方的数字进行模数运算,则CPU必须执行除法,这可能是一种相当昂贵的操作(当然这取决于您使用的数字的大小)。
说到CPU时钟,比较可以并行进行,因为您可以只使用“ xor”操作,所以执行“ x == 10”或“ x == 200000”将花费相同小的CPU时钟。但对于除法来说,这是不可能的,并且一个更大的数字需要更多时间。

1
在许多处理器上,比较操作会将其结果写入全局寄存器,这会阻止它们与使用该寄存器的其他指令并行执行。一些处理器会对该寄存器进行分区或提供“重命名”,从而允许一定程度的并行性。然而,即使有了这个,比较方法仍需要一个分支,而分支不仅不能并行化,还会中断指令预取和推测执行。 - Eric Postpischil
除法比加、减、乘更为复杂,相比之下,如果我理解正确,它需要多个周期。我认为模运算可能是芯片中构建除法的基础。如果可以用减法和乘法代替,请这样做。CPU周期请参考此处:https://embeddedgurus.com/stack-overflow/2011/02/efficient-c-tip-13-use-the-modulus-operator-with-caution/ - Tomachi

3

在汇编语言中,取模操作意味着一种“从未如此简单”的乘法。可以参考一些算法。 分支操作实际上是第二快的指令(跳转是第一),因为只需要最多一个减法来进行比较。


还有一个除法,也是 :-) - Gangnus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接