加法

在二进制下,有异或操作、与操作、进位操作。异或操作是指两个数对应位置相同取0,不同取1;与操作是同为1取1,否则取0;进位就是各位置上的1或0左移若干位。
根据这些操作特性,加法可以分解成这样的过程,先是两个数异或,相当于得到了两个数没有进位的相加结果,然后两个数相与,相当于只有两个位置都是1的情况下该位置才能为1,再进一位,就等效了加法的进位操作,然后将这个无进位的相加结果与进位的结果进行相加,就等于一个完成的加法过程了。需要注意的是,无进位的相加结果和进位的结果的加法过程又可以分解,于是得到了一个递归过程。

1
2
3
4
5
6
7
8
int a = 13;
int b = 42;
while(b != 0) {
int temp = a ^ b;
b = (a & b) << 1;
a = temp;
}
cout << a;

减法

学习四则运算的时候我们就知道,减去一个数等于加上这个数的相反数,二进制中相反数可以这样表示-x = ~x + 1,也就是取反加1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int a = 13;
int b = 42;
int c = ~b;
b = 1;
while(b != 0) {
int tmp = c ^ b;
b = (c & b) << 1;
c = tmp;
}
while(c != 0) {
int tmp = a ^ c;
c = (a & c) << 1;
a = tmp;
}
cout << a;

乘法

乘法运算就像是列一个二进制的乘法竖式一样。假设x是乘数,y是被乘数,那么如果x的当前位是1,就把y直接加到结果中,否则就下一轮操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int a = 13;
int b = 42;
int res = 0;
while(b != 0) {
if((b & 1) != 0) {
int tmp_a = a;
// 执行加法
while( tmp != 0) {
int tmp = tmp_a ^ res;
tmp_a = (res & tmp_a) << 1;
res = tmp;
}
}
a <<= 1;
b >>= 1;
}
cout << res;

除法

除法就是乘法的逆运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int a = 42, b = 4;
int quotient = 0; //商
int remain = a; //余数
for(int i = 31; i > -1; i--) { //除数左移等于被除数右移,还能避免溢出
if((remain >> i) >= b) {
int temp = 1 << i; //1在商中的各位
int temp2;
while(temp != 0) { //求商
temp2 = quotient ^ temp;
temp = (quotient & temp) << 1;
quotient = temp2;
}
temp = ~(b << i); //b左移i位后的相反数
temp2 = 1;
int temp3;
while(temp2 != 0) {
temp3 = temp ^ temp2;
temp2 = (temp & temp2) << 1;
temp = temp3;
}
while(temp != 0) { //求余
temp2 = remain ^ temp;
temp = (remain & temp) << 1;
remain = temp2;
}
}
}
//没有考虑负数情况,若引入负数需要标记结果的正负
cout << "位运算结果: " << quotient << endl;