簡體   English   中英

Python 按位反轉不翻轉位

[英]Python Bitwise Inverse Not Flipping Bits

當使用 pythons inverse ~ 時,似乎這些位沒有像我期望的那樣翻轉。 我相信困惑在於我對 python 如何使用 2 的恭維存儲數字的理解。

myInt = 5 #101
inverse = ~myInt
print(bin(inverse))

Output:-0b110

預期:-0b010 或 -0b10

這不是~運算符的問題,它可以做它應該做的事情,而是使用你用來顯示結果的bin function。

在 Python 中,與大多數計算機系統一樣,負整數在內部以“二進制補碼”二進制表示形式存儲。 這意味着-1由所有1位的序列表示,並且每個較低的 integer 通過正常的 integer 減法規則修改該值。 所以-2是通過從-1中減去1形成的,你會得到一堆1位,然后是一個零作為最后一位。

以下是一些數字及其 4 位二進制補碼表示:

 0 : 0000
 1 : 0001
 2 : 0010
 5 : 0101
-1 : 1111  # this is ~0
-2 : 1110  # this is ~1
-3 : 1101  # this is ~2
-6 : 1010  # this is ~5

與許多其他語言不同,Python 的整數沒有預定義的位長。 它們不是 16 位或 32 位長,就像 C 中的short整數和long整數一樣。 相反,它們是動態調整大小的,根據需要添加更多位以表示越來越大的數字。 當您需要將二進制數字表示為文本時(如bin function 所做的那樣),這會導致一個棘手的情況。 如果您知道您的號碼僅使用 16 位,您可以每次都寫出一個 16 位的字符串,但動態大小的號碼需要不同的解決方案。

事實上,Python 在bin中做了一些不同的事情。 正數用表示其值所需的最短位數寫入。 負數不是用二進制補碼寫的(它們實際上是在內部編碼的方式),而是在它們的絕對值的位表示之前放一個減號。

所以你得到一個像這樣的表,其中按位補碼不明顯:

 0 :    0b0
 1 :    0b1
 2 :   0b10
 5 :  0b101
-1 :   -0b1
-2 :  -0b10
-3 :  -0b11
-6 : -0b110

至於如何獲得負數(如第一個表中的負數)的二進制表示,唯一的好方法是選擇大於任何數字的 2 的冪,並在格式化之前將其添加到所有負值:

MY_MAXINT = 2**4
for v in [0,1,2,5,-1,-2,-3,-6]:
    if v < 0:
        v += MY_MAXINT
    print(format(v, '04b'))

這與二進制補碼編碼負數的方式有關。 任何 integer 的負數表示是通過反轉數字並加一來計算的。

如果您翻轉該邏輯,反轉二進制表示將否定該值並減去一個。 所以 5 的倒數確實應該是 -6。

~5                                                                                                                                                                                                                                  
# -6

由於 Python 沒有為每個 integer 使用固定數量的位,因此無法顯示所有前導零(有無限數量)。 因此,前面有負號, -0b110表示-6

選擇任何固定位數,您可以寫出沒有負數的二進制數。 例如,對於 8 位(一個字節),它將是1111 1010 ,這與您預期的相反。

由於 Python 具有任意大小的有符號整數,因此從概念上講,它們被符號擴展為無窮大。 當我們反轉位0b101時,我們確實得到了0b010 ,但符號擴展也被翻轉:數字以1 s 而不是0 s 的無窮大開始。 而這個1111111....1010的值等於 -6,而不是 -2——因為全 1 的值是 -1,然后我們去掉 4 和 1 位。

一般來說,Python integer 的~x等於-x - 1 (等效於-(x+1) )。 這對於 Python 代碼很少有用,但你永遠不知道:)

你是對的 - 這種行為確實與 Python 如何在twos-complement中存儲負數有關。 在幕后,否定一個數字,將(有效)無限的前導列表附加到二進制表示中。 因此,雖然bin(6)0b110 ,但bin(-6)實際上是0b010 (您可以通過觀察bin(-6 & 7) = 0b010來看到這一點。

這意味着使用~做兩件事; 它翻轉二進制表示的第一位,然后再次翻轉所有位。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM