为什么在此代码中使用按位运算符的加法比算术加法慢得多

时间:2014-03-15 07:45:53

标签: c bit-manipulation bitwise-operators compiler-optimization

我尝试使用我写的按位运算将算术加法与函数进行比较 - 发现后者几乎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

3 个答案:

答案 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次,这需要相当长的时间。

enter image description here

答案 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

但是函数调用应该是主要原因。

相关问题