算法-不使用加減法實現加減法
不使用運算符 + 和 - ,計算兩整數 a 、b 之和。
示例 1:
輸入: a = 1, b = 2
輸出: 3
示例 2:
輸入: a = -2, b = 3
輸出: 1
1、不使用加減法符號實現加法(I)
看到大佬們給出的代碼的確很簡潔,但是同樣的,也很難懂,這裏給出一種非常直觀的解法
主要思路:
1、從1<<0到1<<31做掩碼,遍歷一下,分別與a和b按位與,檢測對應位
2、如果對應位都爲1,那麼進一位:result|=mask<<1;
3、如果對應位只有一個爲1,且result在當前位爲0,那麼將當前位置1
4、如果對應位只有一個爲1,且result在當前位爲1,那麼將當前位置0,再進1位
5、返回result
public int getSum1(int a, int b) {
int result=0;
for(int i=0;i<32;i++){
int mask=1<<i;
if((a&mask)!=0&&(b&mask)!=0){//兩個都是1,必然進位
result|=mask<<1;
}else if(!(((a&mask)==0)&&((b&mask)==0))){
if((result&mask)==0){
result|=mask;
}else{
result&=~mask;//清除原來位
result|=mask<<1;//進一位
}
}
}
return result;
}
上面的寫法其實是沒有問題的,雖然得到mask的時候使用到了++運算符。
++運算符對應的彙編指令映射到X86後其實是INC,而+映射的是ADD。但++看起來還是有點不順眼。
爲了避免這種比較尷尬情況,我們其實可以換個思路,mask其實是可以由自身得到的,即每輪循環過後,mask=mask<<1;直到mask==1<<31的時候終止循環。這樣我們就得到一個純位運算得到的加法。
public int getSum(int a, int b) {
int result=0;
int mask=0;
while(true){
mask=mask==0?1:mask<<1;
if((a&mask)!=0&&(b&mask)!=0){//兩個都是1,必然進位
result|=mask<<1;
}else if(!(((a&mask)==0)&&((b&mask)==0))){//其中某一個爲1
if((result&mask)==0){//如果現在位是0,那麼將現在位變成1
result|=mask;
}else{//如果現在位是1,那麼要將當前位置0,高位放置1
result&=~mask;//清除原來位
result|=mask<<1;//進一位
}
}
if(mask==1<<31){
break;
}
}
return result;
}
2、不使用加減法符號實現加法(II)
大佬們給出的簡潔代碼如下所示:
public int getSum(int a, int b) {
while (b != 0) {
int temp=a^b;//無進位累加值
int carry=(a&b)<<1;//進位值
//a=無進位累加值 b=進位值
a=temp;
b=carry;
}
return a;
}
簡單解釋一下:
1、無進位的加法使用異或實現
2、進位值爲a和b的最高位決定,兩個最高位均爲1,則進1位,而a和b的最高位可以由a&b獲得,這比較好理解,然後如果他們的最高位按位與的結果爲最高位1,那麼向左再移動一位,即爲進位。直到進位爲0,說明運算結束。
3、不使用加減法符號實現減法
如何實現減法呢?這就要考慮到正負數的轉換問題了,負數=正數按位取反+1
public int getSub(int a, int b) {
b=~b;//獲得-b
b++;
while (b != 0) {
int temp=a^b;//無進位累加值
int carry=(a&b)<<1;//進位值
//a=無進位累加值 b=進位值
a=temp;
b=carry;
}
return a;
}