Python獲取數字的二進制值
https://blog.csdn.net/lz0499/article/details/80726315
目標
想要獲取一個整形數字的二進制表示
bin 內置函數
看一下官方的解釋
Convert an integer number to a binary string prefixed with “0b”. The result is a valid Python expression. If x is not a Python int object, it has to define an index() method that returns an integer. Some examples。
-
-
'0b11'
-
-
'-0b1010'
If prefix “0b” is desired or not, you can use either of the following ways.
-
-
('0b1110', '1110')
-
-
('0b1110', '1110')
可以看到bin函數返回二進制數字表示的形式是采用了負號,而不是補碼的形式。那么如何獲得補碼形式的二進制表示呢,很簡單只需要對數值進行與操作就可以。
-
-
'0b1111111111100101'
這個例子手工指定了位數,也可以用下面帶參數的形式
-
def bindigits(n, bits):
-
s = bin(n & int("1"*bits, 2))[2:]
-
return ("{0:0>%s}" % (bits)).format(s)
-
-
-
111111111000010110010111
參考資料:
1、Python bin
2、Two's Complement Binary in Python?
3、integers
轉載於: Python獲取數字的二進制值
十進制到二進制:
def dec2bin(num): l = [] if num < 0: return '-' + dec2bin(abs(num)) while True: num, remainder = divmod(num, 2) l.append(str(remainder)) if num == 0: return ''.join(l[::-1])
十進制到八進制:
def dec2oct(num): l = [] if num < 0: return '-' + dec2oct(abs(num)) while True: num, remainder = divmod(num, 8) l.append(str(remainder)) if num == 0: return ''.join(l[::-1])
十進制到十六進制:
base = [str(x) for x in range(10)] + [ chr(x) for x in range(ord('A'),ord('A')+6)] def dec2hex(num): l = [] if num < 0: return '-' + dec2hex(abs(num)) while True: num,rem = divmod(num, 16) l.append(base[rem]) if num == 0: return ''.join(l[::-1])
Python二進制表示和位操作
鏈接:https://www.jianshu.com/p/3a31065a8e58
我們都知道在計算機中所有的信息最終都是以二進制的0和1來表示,而有些算法是通過操作bit位來進行運算的,這就需要我們了解Python中如何去表示二進制,又如何是進行位運算的。
二進制的表示
首先在Python中可以通過以"0b"或者"-0b"開頭的字符串來表示二進制,如下所示
print 0b101 # 輸出5
print 0b10 # 輸出2
print 0b111 # 輸出7
print -0b101 # 輸出-5
由此可知我們用二進制表示的數字在打印之后會變成我們更為熟悉的十進制數,更容易被人理解。
當我們需要看十進制數字的二進制表示時,可以使用bin函數
bin(5) # 輸出0b101
二進制的位操作
首先一點需要明確的是所有的運算(包括位操作)在計算機內部都是通過補碼形式來進行運算的,關於補碼可以參考文章原碼,反碼和補碼
在Python中提供了如下二進制的位操作:
>> #右移
<< #左移
| #位或
& #位與
^ #位異或
~ #非
下面我們分別來看下:
左移
0b11 << 2 #輸出為12, 即0b1100
5 << 2 #輸出為20, 即0b10100
-2 << 2 #輸出為-8
5 << 64 #輸出為92233720368547758080L
- 以0b11為例,0b11的補碼就是0b11,所以左移就是將所有的0和1的位置進行左移,移位之后將空位補0。
- 負數的左移相對來說就比較復雜,以-2 << 2為例,-2的原碼是10000000000000000000000000000010(32位系統),其補碼為11111111111111111111111111111110,左移之后變為11111111111111111111111111111000,再轉化為原碼即10000000000000000000000000001000,也就是-8,也就是-2*(2**2)=-8
- 左移超過32位或者64位(根據系統的不同)自動轉化為long類型。
- 左移操作相當於乘以2**n,以5 << 3為例,相當於5(2*3),結果為40。
右移
0b11 >> 1 #輸出為1, 即0b1
5 >> 1 #輸出為2,即0b10
-8 >> 3 #輸出為-1
- 在Python中如果符號位為0,則右移后高位補0,如果符號位為1,則高位補1;
- 同樣需要先轉化為補碼再進行計算,以-8 >> 3為例,-8的原碼為10...01000,相應的補碼為11...11000,右移后變為1...1,相應的原碼為10...01,即-1。
- 右移操作相當於除以2**n,8 >> 3相當於8/(2**3)=1
或
0b110 | 0b101 #輸出7,即0b111
-0b001 | 0b101 #輸出-1
同樣是轉化為補碼后再進行或運算, 只要有一位有1就為1。
所以或運算常常用於mask技術中的打開開關,即針對某一位把其置為1
比如將某個數字的第三位置為1,我們可以將mask設置為0b100,然后再或運算
mask = 0b100
0b110000 | mask #turn on bit 3
與
0b110 & 0b011 #輸出2,即0b010
與運算常常用於mask技術的關閉開關,即針對某一位把其置為0
mask = 0b10
0b111111 & mask #turn off bit 2
異或
0b111 ^ 0b111 #輸出0
0b100 ^ 0b111 #輸出3
異或常用於將所有的位反轉
0b1010 ^ 0b1111 #輸出5,即0b0101
非
~0b101 #輸出2,即0b010
~-3 #輸出2
非運算就是把0變1,1變0,唯一需要注意的是取非時符號位也會變換,比如-3,原碼是10...011,補碼是11...101,取非后變為00...010,由於符號位為0,所以對應的原碼即為其本身,即2。
二進制工具
bitarray
關於bit有一個很有用的Packag叫做bitarray,其中bitarray對象可以幫助我們存儲0,1值或者Boolean值,並像list一樣進行操作。
from bitarray import bitarray #初始化一個有10個bit位的數組,初始值為0 a = bitarray(10) #可以像操作list一樣操作bitarray對象 a[1:8] = 1 #bitarray還提供了一些特殊的方法,如:all() #當bitarray中所有的元素都為1時,all()返回為True if a.all(): print "all bits are True."
關於bitarrary的說明詳見Github上的bitarray項目
位運算的應用
常見的應用如判斷奇偶數 X & 0x1,變換符號位 ~X + 1,數字交換等,詳細可以看參考鏈接中的文章
下面筆者想就實際項目中的一個例子來說明位操作的應用。
下表是一個TS Package header的說明(TS流是流媒體行業常用的傳輸格式),我們看到為了減少不必要的浪費,包頭在定義域的時候都是按位進行定義的,那么我們如果想要取相應的域的值,也就需要使用位操作了。
Packet Header(包頭)信息說明
| 序號 | 名稱 |bit數|說明|
|---|---|---|---|---|
|1 | sync_byte | 8bits | 同步字節|
|2 | transport_error_indicator | 1bit | 錯誤指示信息(1:該包至少有1bits傳輸錯誤)|
|3 | payload_unit_start_indicator | 1bit | 負載單元開始標志(packet不滿188字節時需填充)|
|4 | transport_priority | 1bit | 傳輸優先級標志(1:優先級高)|
|5 | PID | 13bits | Packet ID號碼,唯一的號碼對應不同的包|
|6 | transport_scrambling_control | 2bits | 加密標志(00:未加密;其他表示已加密)|
|7 | adaptation_field_control | 2bits | 附加區域控制|
|8 | continuity_counter | 4bits | 包遞增計數器|
我們以取PID值為例,當我們獲取到包頭的字節串之后,我們需要如下幾個步驟:
- 需要取到第2個字節,然后忽略第二個字節的高三位(從表中可以看出高三位為其它信息與PID無關);
- 將第二個字節的后5位數字左移8位,這樣將其移到高位;
- 移位后與第3個字節的數值相加得到PID的值。
要實現第一步,首先就要用到位操作中常用的mask技術,即通過將對應位為0的數值進行&操作
0b10110111 & 0b00011111 #將高位的3位進行mask關閉操作,使得其值被去除
要實現第二步,就需要用到左移操作,左移操作之后與第三個字節的數值相加就是實際的PID值
完整代碼實現如下:
def get_package_pid(package): if package is None: raise Exception("get_package_pid param package is None.") return ((ord(package[1]) & 0x1f) << 8) + ord(package[2])
注:
1, ord()將byte串轉化為對應的數字從而進行位運算;
2, 0x1f是十六進制表示,轉化為二進制就是0b00011111.
參考鏈接:
https://segmentfault.com/a/1190000003789802
https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
https://github.com/wnduan/codecademy-py/blob/master/Bitwise-Operators.md
================ End