剑指Offer - 九度1507 - 不用加减乘除做加法
2013-11-29 20:00
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
输入可能包含多个测试样例。
对于每个测试案例,输入为两个整数m和n(1<=m,n<=1000000)。
对应每个测试案例,输出m+n的值。
3 4 7 9
7 16
题意分析:
求两个数的和而不能用加减乘除,很明显又得借助位运算了。回想一下学Verilog时加法器的实现,能记住下面这两个关系:
sum = bit1 ^ bit2 ^ carry
carry' = (carry & bit1) | (bit1 & bit2) | (bit2 & carry)
其中sum是当前位的和,bit1和bit2是两数的当前二进制位,carry是上一位的进位,carry'是这一位的进位。
简单解释一下俩式子:
式子1:加法和异或的区别就在于加法可以进位,而异或不进位。
式子2:三个数只要有两个以上的‘1’就有进位了,所以是三个与的或。
接下来就是逐位相加,将进位carry一直向上传递了。要注意别让最高位的carry丢失掉,除非是超出了本身数据能表示的范围。
既然是写个加法器,依然本着写Verilog的原则,拒绝for循环。以下是ac的代码。
1 // 653474 zhuli19901106 1507 Accepted 点击此处查看所有case的执行结果 1020KB 1439B 10MS 2 // 201311190151 3 #include <cstdio> 4 using namespace std; 5 6 void cal_onebit(const int m, const int n, int i, int &carry, int &res) 7 { 8 res = (res | 9 ( 10 (m & (1 << i)) ^ 11 (n & (1 << i)) ^ 12 (carry << i) 13 ) 14 ); 15 carry = 16 ( 17 (m & (1 << i)) & 18 (n & (1 << i)) 19 ) || 20 ( 21 (n & (1 << i)) & 22 (carry << i) 23 ) || 24 ( 25 (carry << i) & 26 (m & (1 << i)) 27 ); 28 } 29 30 int main() 31 { 32 int m, n; 33 int res; 34 int carry; 35 36 while(scanf("%d%d", &m, &n) == 2){ 37 carry = 0; 38 res = 0; 39 cal_onebit(m, n, 0, carry, res); 40 cal_onebit(m, n, 1, carry, res); 41 cal_onebit(m, n, 2, carry, res); 42 cal_onebit(m, n, 3, carry, res); 43 cal_onebit(m, n, 4, carry, res); 44 cal_onebit(m, n, 5, carry, res); 45 cal_onebit(m, n, 6, carry, res); 46 cal_onebit(m, n, 7, carry, res); 47 cal_onebit(m, n, 8, carry, res); 48 cal_onebit(m, n, 9, carry, res); 49 cal_onebit(m, n, 10, carry, res); 50 cal_onebit(m, n, 11, carry, res); 51 cal_onebit(m, n, 12, carry, res); 52 cal_onebit(m, n, 13, carry, res); 53 cal_onebit(m, n, 14, carry, res); 54 cal_onebit(m, n, 15, carry, res); 55 cal_onebit(m, n, 16, carry, res); 56 cal_onebit(m, n, 17, carry, res); 57 cal_onebit(m, n, 18, carry, res); 58 cal_onebit(m, n, 19, carry, res); 59 cal_onebit(m, n, 20, carry, res); 60 printf("%d\n", res); 61 } 62 63 return 0; 64 }