从执行时间的角度来看,使用模数运算符更有利或者手动方式这样做,如果我应该做模数的事情很多次,大约10 ^ 6次?
手动做(编号%mod_number):
while(number >= mod_number) {
number = number - mod_number;
}
使用%operator:
执行相同的操作number = number % mod_number;
根据我的测试,手动操作可以提供更好的时间性能。
如何定义模数运算符?我知道负数的输出是实现定义的,我问运算符的工作情况,即它的复杂性,以便我可以证明更好的手动性能。
注意:该问题专门用于C.实施
代码段:
for (j = 0; j < idx; j++) {
num = mark[j];
dif = k - num;
if (dif < 0) dif = (-1 * dif) + 100;
many = count[num];
prev = ap[dif][k];
ap[dif][k] = ap[dif][k] + ap[dif][num];
//the manual way here works faster than %
if (ap[dif][k] >= mod) ap[dif][k] -= mod;
ap[dif][k] += many;
if (ap[dif][k] >= mod) ap[dif][k] -= mod;
sum = (sum + ap[dif][k]);
if (sum >= mod) sum -= mod;
sum = sum - prev;
}
上述循环用&lt; idx&#39;执行2 *(10 ^ 5)* t次。每个人逐渐增加到100岁。使用t = 10.
答案 0 :(得分:3)
如果number
比mod_number
大许多倍,循环效率会更高,我会感到非常惊讶。您可能使用的任何CPU都具有内置除法运算,该运算在常量时间内返回商和余数,这将用于实现%
运算符。你的循环需要O(number/mod_number)
时间。
我建议你看一下两个版本生成的汇编代码,你会看到这个。
答案 1 :(得分:1)
这取决于实施。在没有给定系统的情况下讨论性能是毫无意义的。
模数运算符很可能通过CPU的除法指令实现,与其他CPU指令相比,它在大多数CPU上相对较慢。但是,像您示例中的循环似乎不太可能更有效。
更有可能的是,您遇到的性能差异与错误的优化设置或错误的基准测试有关。
答案 2 :(得分:0)
根据我的经验,使用模数运算符应该会给你更好的表现。编写C编译器的人应该考虑优化他们正在执行的操作。
但是你的测试结果显示了另一个,它可能取决于你编写的代码。找到原因会更容易吗?如果你出示你的代码......
答案 3 :(得分:0)
您显示的示例(不是顶部的while
循环,底部的代码段)是“除数”最多只减去一次的情况。这基本上是一种情况,其中“重复”减法(0或1次,重复减法的特殊情况)可以(并且通常是,但不是必然)比基于分区的模更快。显然,它取决于目标上的除法速度,测试/分支(或测试/谓词指令)在目标上的速度有多快,而在分支的情况下,它甚至取决于分支的可预测程度。
编译器不太可能进行优化(但这并非不可能),因为只有知道减法最多只会发生一次(或者可能多于一次,如果除法特别慢,目标,但仍然需要一些低限度),这对于编译器来说通常很难找到。
给一些real life numbers,在Haswell 32位有符号分区(因此也是模数)上需要22到29个周期,而分支错误预测可能需要20个周期,但这是最坏的情况和分支不应该一直误预测。此外,你可以避免分支(如果它被严重预测)并做这样的事情(没有测试,只是为了给你一些想法)
sub eax, edx
lea edx, [eax + edx]
cmovl eax, edx
这应该只需要大约4个周期,与任何可预测性无关。如果可以很好地预测,使用分支可能会更快。