# Bitwise > https://hackmd.io/@sysprog/binary-representation#%E8%A7%A3%E8%AE%80%E8%A8%88%E7%AE%97%E6%A9%9F%E7%B7%A8%E7%A2%BC ## NOT operator ``` x = ~x ``` ## 一補數、二補數 單位元為0,對應到10進制正負換算 ``` x = ~x + 1 // x = -x ``` | 一補數(無號數/有號數) | 二補數(無號數/有號數) | 2進制 | | -------- | -------- | -------- | | 0(+0) | 0 | 0000 | | 1(1) | 1(1) | 0001 | | 2(2) | 2(2) | 0010 | | 3(3) | 3(3) | 0011 | | 4(4) | 4(4) | 0100 | | 5(5) | 5(5) | 0101 | | 6(6) | 6(6) | 0110 | | 7(7) | 7(7) | 0111 | | 8(-7) | 8(-8) | 1000 | | 9(-6) | 9(-7) | 1001 | | 10(-5) | 10(-6) | 1010 | | 11(-4) | 11(-5) | 1011 | | 12(-3) | 12(-4) | 1100 | | 13(-2) | 13(-3) | 1101 | | 14(-1) | 14(-2) | 1110 | | 15(-0) | 15(-1) | 1111 | ## Number of 1 Bits (計算有幾個位元是 1 ) ``` // __builtin_popcount // 僅適用32位元無號數 unsigned int count_1_bit(unsigned int x) { x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); return x; } ``` ## Bit Reversal (顛倒位元順序) ``` // 僅適用32位元無號數 unsigned int bit_reverse(unsigned int x) { x = ((x >> 1) & 0x55555555) | ((x << 1) & 0xaaaaaaaa); x = ((x >> 2) & 0x33333333) | ((x << 2) & 0xcccccccc); x = ((x >> 4) & 0x0f0f0f0f) | ((x << 4) & 0xf0f0f0f0); x = ((x >> 8) & 0x00ff00ff) | ((x << 8) & 0xff00ff00); x = ((x >> 16) & 0x0000ffff) | ((x << 16) & 0xffff0000); return x; } ``` ## Least Significant 1 Bit (找到最低位的 1 ) ``` int least_significant_1_bit(int x) { return x & -x; } ``` ## Power of 2 Test (判斷一個正整數是否為 2 的次方) ``` bool is_power_of_2(int x) { return !(x & (x-1)); // x & (x-1)消去最低位的1 } ``` ## XOR Swap (交換兩個 int 變數) ``` // 注意:比直接交換還要慢。 void swap(int& x, int& y) { x = x ^ y; y = x ^ y; x = x ^ y; } // 下面的寫法有暫存變數存取順序問題。 // Unspecified Behavior,不同的編譯器可能產生不同結果。 // 千萬不要如此取巧。 void swap(int& x, int& y) { x ^= y ^= x ^= y; } ``` ``` void xorSwap(int *x, int *y) { *x ^= *y; *y ^= *x; *x ^= *y; } ``` 需要這種手法的情境: 指令集允許 XOR swap 產生較短的編碼 (某些 DSP); 考慮到暫存器數量在某些硬體架構 (如 ARM) 非常有限,register allocation 就變得非常棘手,這時透過 XOR swap 可降低這方面的衝擊; 在微處理器中,記憶體是非常珍貴的資源,此舉可降低記憶體的使用量; 在加解密的實作中,需要常數時間的執行時間,因此保證 swap 兩個數值的執行成本要固定 (取決於指令週期數量); ## Missing Number Problem (檢查缺少的正整數) 陣列放入 1 到 10 的正整數,但是少了一個。找出少了哪一個。 使用 Counting Sort ,雖然時間複雜度低,但是空間複雜度高。 ``` int array[9] = {2, 3, 5, 9, 4, 6, 10, 8, 1}; int find_lack_number() { int n = 0; // 1到10全部xor起來 for (int i=0; i<10; ++i) n ^= i; // 陣列裡的數字全部xor起來,與先前結果做xor。 for (int i=0; i<9; ++i) n ^= array[i]; return n; } ``` ## 英文大小寫換算 ``` ('a' ^ ' ') // 得到 'A' ('A' ^ ' ') // 得到 'a' ``` ## 取字串,判斷NULL位置 ``` int8_t GetNull(int8_t X) { int8_t temp1, temp2, temp3, temp4; int8_t inverse; temp1 = (X) - 0x01; //X為0時,0 - 1 = -1 inverse = ~(X); //X為0時,對0做not運算 = -1 temp2 = temp1 & inverse; //取前兩個條件相同的地方 temp3 = temp2 & 0x80; //確認是否為-1 temp4 = (((X) - 0x01) & ~(X) & 0x80); return (((X) - 0x01) & ~(X) & 0x80); return (((X) - 0x01010101) & ~(X) & 0x80808080); //可一次做4個byte } ``` ![](https://hackmd.io/_uploads/Hk-tvsWCh.png) ## Toggle a bit by XOR ``` unsigned char c ^= (1 << n); ``` ## XOR 特徵 如大值與小值都為同為正/負整數時做 and bitwise運算。TURE(> 0),則XOR為大減小。FALSE(== 0),則XOR為加法。 ``` if(a & b) { int c = a ^ b; //c = a - b } else { int c = a ^ b; //c = a + b } ``` ![](https://hackmd.io/_uploads/HyzRF3Z03.png) ## align up ``` static inline uintptr_t align_up(uintptr_t sz, size_t alignment) { uintptr_t and_temp; uintptr_t xor_temp; uintptr_t add_mask; uintptr_t not_mask; uintptr_t normal_temp; if ((alignment & (alignment - 1)) == 0) { /* Check if alignment is a power of two */ uintptr_t mask = alignment - 1; //剛好2的指數-1後的值,其二進制都為1。作為判斷是否為2的指數。 add_mask = (sz + mask); not_mask = ~mask; and_temp = add_mask & not_mask; //捨去alignment位數 normal_temp = (((sz + mask) / alignment) * alignment); return (sz + mask) & ~mask; return (((sz + mask) / alignment) * alignment); } return sz; // Return sz unchanged if alignment is not a power of two } ``` ![](https://hackmd.io/_uploads/SypoC3-Ah.png) ## 加法器 > https://kopu.chat/%E4%BB%A5c%E5%AF%A6%E4%BD%9C%E4%BA%8C%E9%80%B2%E4%BD%8D%E5%8A%A0%E6%B3%95/ ``` int add(int a, int b) { if (b == 0) return a; int sum = a ^ b; /* 相加但不進位 */ int carry = (a & b) << 1; /* 進位但不相加 */ return add(sum, carry); } ```