位运算实现加减乘除运算——超详细C语言描述

位运算实现整数加减乘除运算——C语言描述

本文将从位运算的种类、原理、运用入手,详细介绍如何仅使用位运算实现整数的加减乘除运算,代码采用C语言实现。

1.位运算

我们知道,程序中的所有数据在计算机内存中都是以二进制的形式存放的,所谓的位运算就是直接对整数在内存中的二进制位进行操作。位运算是早期计算机的基础,正因如此,在计算机组成原理课程中我们经常会注意到位运算的存在。时至今日,不管是在C语言,还是在Java,或者其他语言,都会经常用到位运算。
具体说来,位运算一共有七种,分别是按位与、按位或、按位异或、按位取反、左移、带符号右移(算术右移)、无符号右移(逻辑右移)。
下表这些位运算的符号以及语言描述。

含义 Pascal C Java
按位与 a and b a & b a & b
按位或 a or b a | b a | b
按位异或 a xor b a ^ b a ^ b
按位取反 not a ~a ~a
左移 a shl b a << b a << b
有符号数右移 a shr b a >> b a >> b
无符号数右移 / / a >>> b

2. 位运算实现加法

2.1 基本思路

使用位运算实现加法时,基本思路与计算机组成原理中的加法器类似,使用位运算a ^ b来实现没有进位的本位和,用a & b来获得需要进位的位置,则(a & b << 1)则表示进位加1后的数,再用或运算求本位和,直至(a & b) == 0即没有进位为止。

2.2 代码实现

int Add(int a, int b){
	return b ? Add(a ^ b, (a & b) << 1) : a;
}

3. 位运算实现减法

3.1 基本思路

在进行位运算实现减法的过程中,首先应该注意到取反运算中的一个很重要的特点,即~b = -(b+1)。根据这个特点,我们可以很简单的利用位运算求得一个数的相反数,即利用Add(~b, 1)。而由于整数的减法实际上就是加法的逆运算,即a-b = a+(-b)。故减法的实现就非常明了了。

3.2 代码实现

int Minus(int a, int b){
	return Add(a, Add(~b, 1));
}

4. 位运算实现乘法

4.1 基本思路

一开始考虑到乘法其实是加法的延续,是一种累加运算,只要将被乘数进行乘数次相加即可,但这样的做法存在一个很明显的问题即当乘数很大时需要进行多次加法运算。下面介绍一种改进的乘法思路,这种思路由手作乘法的过程的方法而来。在进行手动乘法时,我们根据乘数的尾数是否为1来确定是否需要相加。即若乘数的尾数是1,那么就要加上被乘数,否则则不需要加上被乘数。在本次判断之后,我们需要将被乘数左移一位,乘数逻辑右移一位。整个过程在乘数为0时停止。
同时需要注意符号的问题,这里我们首先进行绝对值的运算,再通过a^b是否小于0判断符号的异同性。

4.2 代码实现

int Multiply(int a, int b){
    int a1 = a > 0 ? a : Add(~a, 1);
    int b1 = b > 0 ? b : Add(~b, 1);
    int sum = 0;
    while(b1){
        if(b1 & 0x1){
            sum = Add(sum, a1);
        }
        a1 = a1 << 1;
        b1 = b1 >> 1;
    }
    if((a ^ b) < 0)
        return Add(~sum, 1);
    else return sum;
}

在编写代码时,犯了一个低级错误,a1 = a1 << 1,这句我没写前面的a1=,导致程序一直卡死。

5 位运算实现除法

5.1 基本思路

跟加法、减法一样,除法是乘法的逆运算,那么除法就是做有限次的减法,直到被减数小于减数为止。这种思路类似于乘法中的简单思路,问题同样是在被除数远大于除数时,需要做多次除法。
改良的除法思路如下,考虑到int型整数占32位,那么用i = 31开始比较被除数与除数的2i的大小,若被除数大,则在商处直接加上i从而减小减法的次数。

5.2 代码实现

int Divide(int a, int b){   
	int quotient = 0;
    if(!b){
        cout << "Error" << endl;
        return 1;
    }
    for(int i = 31; i --; i > 0){
        if((a >> i) >= b)
        {
            quotient = Add(quotient, 1 << i);
            a = Minus(a, b << i);
        }
    }
    if((a ^ b) < 0)
        quotient = Add(~quotient, 1);
    return quotient;
}

该段代码有几个需要注意的地方,第一,需要对除数进行非零判断;第二,在判断时,应该a右移而非b左移,因为b << i可能会溢出;第三,并不是简单的加i,而是加上1 << i。

你可能感兴趣的:(c语言)