我尝试使用我写的按位运算将算术加法与函数进行比较 - 发现后者几乎10x
慢了。这种速度差异的原因是什么?由于我在循环中添加相同的数字,编译器是否会在第一种情况下将其重写为更优的东西?
使用算术运算:
int main()
{
clock_t begin = clock();
int x;
int i = 1000000000;
while(i--) {
x = 1147483000 + i;
}
printf("%d\n", x);
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("time spent = %f\n", time_spent);
return 0;
}
输出:
1147483000
time spent = 3.520000
使用按位运算符:
while loop
内的行替换为:
x = add(1147483000, i);
这里是add
函数:
int add(int x, int y) {
while(y != 0) {
int carry = (x & y);
x = x ^ y;
y = carry << 1;
}
return x;
}
输出:
1147483000
time spent = 32.940000
答案 0 :(得分:5)
整数运算通常在很少的时钟周期内在硬件中执行。
您将无法在软件中接近这种性能。使用按位运算的实现涉及函数调用和循环。您执行的按位操作通常会花费与算术相似的时钟周期数。
每次迭代都要执行三次按位运算。坦率地说,我很震惊,这里只有10倍。
我也想知道你的编译器设置是什么,特别是任何优化。一个好的编译器可以消除算术版本中的while循环。对于性能比较,您应该比较优化代码。看起来好像你可能没有这样做。
很难知道你在这里想要达到的目标,但是不要期望超过硬件算术单元的性能。
答案 1 :(得分:4)
你已经取代了这个:
x = 1147483000 + i;
用这个:
while(y != 0) {
int carry = (x & y);
x = x ^ y;
y = carry << 1;
}
当然,你会得到一个巨大的减速!两个整数的+
是一个汇编指令。您的while
循环执行许多指令,有效地在软件中模拟硬件执行添加时的功能。
详细说明,这就是full adder的样子。通过32位加法,ALU包含32个此单元级联。这些硬件元件中的每一个都具有非常小的延迟。电线的延迟可以忽略不计。因此,如果软件将两个32位数字相加,则只需很短的时间。
另一方面,如果您尝试手动模拟添加,则会使CPU进入内存,获取并解码一些指令32次,这需要相当长的时间。
答案 2 :(得分:1)
使用函数调用替换add时: 调用函数比简单添加更耗时,因为函数调用与堆栈操作相关联。
在该功能中,您将使用三个按位操作替换添加 - 它们与添加的比较速度可能是一个问题 - 尽管没有测试也没有确认。你可以在这里发布三个按位操作的单独时间吗?:
1
//tic
while(i--) {
int carry = (x & y);
}
//toc
2
//tic
while(i--) {
x = x ^ y;
}
//toc
3
//tic
while(i--) {
y = carry << 1;
}
//toc
但是函数调用应该是主要原因。