題目
寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。
# -*- coding:utf-8 -*-
class Solution:
def Add(self, num1, num2):
# write code here
題目解析:
要求不使用四則運算符,那麼思路就是位運算,也就是python最底層實現四則運算符的方法
位運算概覽
符號 | 描述 | 運算規則 |
---|---|---|
& | 與 | 兩個位都爲1時,結果才爲1 |
| | 或 | 兩個位都爲0時,結果才爲0 |
^ | 異或 | 兩個位相同爲0,相異爲1 |
~ | 取反 | 0變1,1變0 |
<< | 左移 | 各二進位全部左移若干位,高位丟棄,低位補0 |
>> | 右移 | 各二進位全部右移若干位,對無符號數,高位補0,有符號數,各編譯器處理方法不一樣,有的補符號位(算術右移),有的補0(邏輯右移) |
假設num1 =11,num2 = 9
11 => 1011
+ 9 => + 1001
------- --------
20 10100
在位運算中 ^ 和 & 分別產生以下結果
1011 1011
^ 1001 & 1001
--------- ------------
0010 1001
1011 //
+ 1001 //
---------
00010 // 先 1011 ^ 1001 合併得到未進位的結果( 1011 ^ 1001 = 00010 )
10010 // 1011 & 1001 = 1001 不爲 0 存在進位,故執行 1001 << 1 得到進位後的結果 10010
---------
10000 // 通過 00010 ^ 10010 合併得到未進位的結果( 00010 ^ 10010 = 10000 )
00100 // 00010 & 10010 = 00010 不爲 0 存在進位,故執行 00010 << 1 得到進位後的結果 00100
---------
10100 // 通過 10000 ^ 00100 合併得到未進位的結果( 10000 ^ 00100 = 10100 )
00000 // 10000 & 00100 = 00000 ,此時結束運算。
---------
# -*- coding:utf-8 -*-
class Solution:
def Add(self, num1, num2):
# write code here
while num2:
# 由於python長整數類型可以表示無限位,所以需要人爲設置邊界,避免死循環。
result = (num1 ^ num2) & 0xffffffff
carry = ((num1 & num2) << 1) & 0xffffffff
num1 = result
num2 = carry
if num1 <= 0x7fffffff: # 小於0x7fffffff(max_int) 爲正數
result = num1
else:
"""
num1 > 0x7fffffff ,則表示 num1二進制下首位爲1 即是負數
負數是以補碼形式存儲的,python的取反運算結果是補碼。
前面用 num1 ^ 0xFFFFFFFF 相當於無視符號位,直接轉爲無符號數,
此時解釋器已經不認識補碼了。後面再用一次取反,強調是補碼
"""
result = ~(num1^0xffffffff)
return result
知識補充
在Python內部對整數的處理分爲普通整數和長整數,普通整數長度爲機器位長,通常都是32位,超過這個範圍的整數就自動當長整數處理,而長整數的範圍幾乎完全沒限制所以long類型運算內部使用大數字算法實現,可以做到無長度限制。
每個十六進制數4bit,因此8位16進制是4個字節,剛好是一個int整型
F的二進制碼爲 1111
7的二進制碼爲 0111
這樣一來,整個整數 0x7FFFFFFF 的二進制表示就是除了首位是 0,其餘都是1
就是說,這是最大的整型數 int(因爲第一位是符號位,0 表示他是正數)
同理: 32位的全1數字可爲0xffffffff
參考鏈接:
牛客網
聊聊使用位運算來實現加法(老物)