位操作有太多的神奇寫法,這裏總結一部分。
1. 無算術運算符的加法 Add two numbers without using arithmetic operators
(1) 題意
如果有一個題目,要求我們實現一個 add
函數,不使用包括 +,++,-,--,..
等算術運算符,完成兩個整型數的相加。
兩個比特的相加,可以用 ^
來代替(可能存在進位);進位一個比特,可以用 &
來實現。類似的,數字邏輯中,完成兩個單獨的比特相加的是半加器(half adder
) ,通過半加器的串聯,可以實現全加器。
一個樸素的思維是,從最高位開始,x
和 y
的每一位相異或 ^
,如果有進位,則對結果的高位異或 1
,有進位就繼續。或者從最低位開始?這樣想太麻煩了。
(2) 思路
我們直接對 x
和 y
進行操作,相當於並行進位。
(1) 如果 x
和 y
在每一個二進制位都不同,x^y
就是 x+y
。如:0101 ^ 1010 = 1111
。
(2) 如果存在相同的二進制位(都是 1
),那麼需要用 &
來將其吸納進去。都是 0
的情況無關緊要。
x = 7 = 0000 0111
y = 5 = 0000 0101
x+y = 0000 1100
x=x^y = 0000 0010 //x^y爲0的二進制位代表的x,y對應位可能都是0, 或都是1
c=x&y = 0000 0101 //x&y爲1的二進制位標記出x,y對應位都是0的情況, 這代表這些位都需要進位
//進位: y = c << 1 = 0000 1010, 即準備對這些位的高一位進行“加法”
//加法的^, 遞歸進行
x=x^y = 0000 1000
c=x&y = 0000 0010
//進位: y = c << 1 = 0000 0100
//加法的^
x=x^y = 0000 1100 //此時x和y在每一個二進制位都不同
c=x&y = 0000 0000 //c=x&y=0, 不用再進位
(3) 模板代碼
下面的寫法可以作爲模板。
// C++ Program to add two numbers without using arithmetic operator
#include <bits/stdc++.h>
using namespace std;
int add(int x, int y) {
//iterate utill there is no carry
while (y) {
//the carry contains all the common bits of x and y
int carry = x & y;
//now, x is the SUM of bits of x and y
//where at least one of the bits is not set
x = x ^ y;
//carry is right-shifted by 1 so that adding it to x
y = carry << 1;
}
return x;
}
int main() {
cout << add(15, 32);
return 0;
}
遞歸版:
int add(int x, int y) {
if (y == 0) return x;
return add(x ^ y, (x & y) << 1);
}