Python和Go語言在右移與運算上的差異記錄
二進位制右移規則 |
---|
把一個二進位制數右移N位,規則為: 除符號位外,全部右移N位, 如果數字是一個無符號數值,則用0填補最左邊的N位, 如果數字是一個有符號數值,則用1填補最左邊的N位, 也就是說如果數字原先是一個正數,則右移之後在最左邊補N個0;如果數字原先是個負數,則右移之後在最左邊填補N個1。 例子: 0000 0010 >> 1 = 0000 0001 0000 1010 >> 2 = 0000 0010 1000 0010 >> 1 = 1100 0001 1000 1010 >> 3 = 1111 0001 上面的例子,正數的容易理解,為什麼負數的是填補N個1呢,解釋如下: 負數在計算機內部是以補碼形式存放的, 1000 0010是一個負數,它的原碼是1111 1110,也就是說它不是表示-2,而是表示-126; 證明1000 0010右移1位後是1100 0001呢, 1000 0010的原碼是1111 1110,對原碼右移1位,為1011 1111,(也就是-63),再換成補碼,為1100 0001, 可以看出,1000 0010右移1位確實是1100 0001,也就是說, 換句話說,原碼(正數)移位時,缺失位補0; 補碼(負數)移位時,缺失位補符號位,當然正數時亦可(正數補碼與原碼完全一樣)。 如果數字原先是個負數,則右移之後在最左邊填補N個1。 |
二進位制與運算 |
---|
程式中的所有數在計算機記憶體中都是以二進位制的形式儲存 的。位運算就是直接對整數在記憶體中的二進位制位進行操作 。比如,and運算本來是一個邏輯運算子 ,但整數與整數之間也可以進行and運算。舉個例子,6的二進位制是110,11的二進位制是1011,那麼6 and 11的結果就是2,它是二進位制對應位進行邏輯運算的結果(0表示False,1表示True,空位都當0處理)。 110 AND 1011 --------------- 0010 --> 2 有人會說,計算6 and 11沒有什麼實際意義啊。這一系列的文章就將告訴你,位運算到底可以幹什麼,有些什麼經典應用,以及如何用位運算優化你的程式。 |
運算說明 |
---|
=== 1. and運算 & === and運算通常用於二進位制的取位操作 ,例如一個數 and 1的結果就是取二進位制 的最末位。這可以用來判斷一個整數的奇偶,二進位制的最末位為0表示該數為偶數 ,最末位為1表示該數為奇數。 相同位的兩個數字都為1,則為1;若有一個不為1,則為0。 00101 11100 (&;或者and) ---------------- 00100 === 2. or運算 | === or運算通常用於二進位制特定位上的無條件賦值 ,例如一個數or 1的結果就是把二進位制最末位強行變成1。如果需要把二進位制最末位變成0,對這個數or 1之後再減一就可以了,其實際意義就是把這個數強行變成最接近 的偶數。 相同位只要一個為1即為1。 00101 11100 (|或者or) ---------------- 11101 === 3. xor運算 ^ === 異或的符號是^。按位異或運算, 對等長二進位制模式按位或二進位制數的每一位執行邏輯按位異或操作. 操作的結果是如果某位不同則該位為1, 否則該位為0. xor運算的逆運算是它本身,也就是說兩次異或同一個數最後結果不變,即(a xor b) xor b = a。xor運算可以用於簡單的加密,比如我想對我MM說1314520,但怕別人知道,於是雙方約定拿我的生日19880516作為金鑰 。1314520 xor 19880516 = 20665500,我就把20665500告訴MM。MM再次計算20665500 xor 19880516的值,得到1314520。 相同位不同則為1,相同則為0。 00101 11100 (^或者xor) ---------------- 11001 運算結果 x <- x # y y <- x @ y x <- x @ y 執行了第一句後x變成了x # y。那麼第二句實質就是y <- x # y @ y,由於#和@互為逆運算,那麼此時的y變成了原來的x。第三句中x實際上被賦值為(x # y) @ x,如果#運算具有交換律,那麼賦值後x就變成最初的y了。這三句話的結果是,x和y的位置互換了。 === 4. not運算 ~ === not運算的定義是把記憶體中的0和1全部取反。使用not運算時要格外小心,你需要注意整數型別有沒有符號。如果not的物件是無符號整數 (不能表示負數),那麼得到的值就是它與該型別上界 的差,因為無符號型別的數是用00到$FFFF依次表示的。下面的兩個程式(僅語言不同)均返回65435。 === 5. shl運算 << === a shl b就表示把a轉為二進位制後左移b位(在後面添b個0)。例如100的二進位制為1100100,而110010000轉成十進位制是400,那麼100 shl 2 = 400。可以看出,a shl b的值實際上就是a乘以2的b次方,因為在二進位制數後添一個0就相當於該數乘以2。 通常認為a shl 1比a * 2更快,因為前者是更底層一些的操作。因此程式中乘以2的操作請儘量用左移一位來代替。 定義一些常量 可能會用到shl運算。你可以方便地用1 shl 16 - 1來表示65535。很多演算法和資料結構要求資料規模必須是2的冪,此時可以用shl來定義Max_N等常量。 === 6. shr運算 >> === 和shl相似,a shr b表示二進位制右移b位(去掉末b位),相當於a除以2的b次方(取整)。我們也經常用shr 1來代替div 2,比如二分查詢 、堆的插入操作等等。想辦法用shr代替除法運算可以使程式效率大大提高。最大公約數的二進位制演算法用除以2操作來代替慢得出奇的mod運算,效率可以提高60%。 |
優先順序順序 | |
---|---|
1 |
~ |
2 |
<<、>> |
3 |
& |
4 |
^ |
5 |
| |
6 |
&=、^=、|=、<<=、>>= |
python版本右移拆分 |
---|
print(bin(2234),bin(31),2234>>7,2234>>7&31 ),得到執行結果:0b100010111010 0b11111 17 2234的二進位制是0b100010111010,右移7位是0b10001 然後31的二進位制是:0b11111 那麼2234>>7&31執行先後順序,2234>>7是0b10001,然後0b10001&31,就是 0b11111 0b10001 &的規則,是相同為1,不同為0,得到0b10001,則為17。 |
go版本右移拆分 |
---|
func Get_dbno(tbname string,key uint,split1 uint,split2 uint)(dbno uint){ var dbno1= key >> split1 dbno=dbno1 & split2 return } |