# 位元運算 ###### tags: `C++Book` ## 負數表示 :::info **補數** 補數(Complement):是指兩數字加起來等於某數時,則二數互為某數的補數。 例如3的10補數為7,7的10補數為3。 ::: ### 1的補數(1‘ Complement): :::info 指兩數的和為每個bit 為 1,則此兩數互為1 的補數,即1和0互為1的補數。 ::: ==即將原數的0變1,1變0,即為 ~b == | 原數為 | 1 | 0 | 1 | 1 | 0 | 1 | |---|---|---|---|---|---|---|---| | 1補數為 | 0 | 1 | 0 | 0 | 1 | 0 | ### 2的補數(2’ Complement): :::info 指二兩數的和使每一位均為0而產生溢位(進位)。 ::: ==先取該數的1補數,再加1即可,即為 -x+1== | 原數為 | 0 | 1 | 1 | 0 | 1 | |---|---|---|---|---|---|---| | 1補數為 | 1 | 0 | 0 | 1 | 0 | | 1的補數再加1 | 1 | 0 | 0 | 1 | 1 | 數x加數x的1補數 →.....1111111 再加1 → 全部進位 ### MSB :::info 符號位元 ::: 補數系統裡是將 MSB (最左邊的位元),表示符號位元,剩下的位元才拿來算值,是負數才須要轉補數。 將 MSB 符號位元視為區別到底「此數為正數」還是「此數為某數的某種補數」。 ## 奇數判斷 運用位元遮罩,右邊的1 → 00000...001 x除了最後一個位元都會被 _ and 0遮罩掉 ```cpp (x & 1)//如果是奇數值是true ``` ## 二的次冪 **2nx** ```cpp x << n ``` 利用左移運算,即可輕易將整數 x 乘以 2^n。 **x/2n** ``` cpp x >> n ``` 利用右移運算,即可輕易將整數 x 除以 2n。需要注意的是,該除法會**直接捨去浮點數部分**。 :::warning 注意overflow ::: ## 末端連續N個1 ```cpp (1 << n) - 1 ``` ## 尋找最低位的1 ```cpp x & -x ``` **對任何數加上 1,在位元的意義即為將最低位的位元 0 變為位元 1,且低於該位的位元1都將被設定為 0** `ex 011111 + 1 → 100000` x的最低位1為 & (~x的最低位0 →通過+1變成 1) → 只有最低位1為1,其餘為零(高於最低1的不會被改,一定是0) x=10100 ~x=01011 -x=01==1==00 x&-x=00100 ### 是否為二的次冪 ```cpp (x & -x) == x ``` 如果只有1個1,那最低1必定為他本身 ## 將第n個位元設定為1 or 0 ```cpp x|(1<<n) x&~(1<<n) ``` ## 整數交換 ```cpp x^=y^=x^=y ``` 拆開來看即為: ```cpp x = x ^ y; y = y ^ x;...(1) x = x ^ y;...(2) ``` 這個方法基於 xor(^) 的特性: - 任何數對本身做 xor 運算都會等於 0 - 任何數對 0 做 xor 運算都會等於本身 令x,y原本的值為x',y' (1)中,y=y'^y'^x', y'^y'必為0,求x'^0 1^0=1,0^0=0,如此y=x' (2)中,x=x'^y'^x',同理x=y' ## 引用 >[https://welkinchen.pixnet.net/blog/post/41360237-%E8%A3%9C%E6%95%B8](https://welkinchen.pixnet.net/blog/post/41360237-%E8%A3%9C%E6%95%B8) >[https://blog.kuoe0.tw/posts/2012/01/26/bitwise-operation-utlization/](https://blog.kuoe0.tw/posts/2012/01/26/bitwise-operation-utlization/)