XOR — 神奇的按位運算符

1、異或運算符

在數字邏輯中,邏輯算符異或(exclusive or)是對兩個運算元的一種邏輯分析類型,符號爲 XOR 或 ⊕(編程語言中經常使用 ^)。但與通常的邏輯或不一樣,異或算符的值爲真僅當兩個運算元中恰有一個的值爲真,而另一個的值爲非真。javascript

1.1 異或運算的表示形式

名稱 符號
數學符號
英文簡稱 xor
程序符號 ^

1.2 異或運算的真值表

異或運算 p ⊕ q 的真值表以下:java

p q
T T F
T F T
F T T
F F F

不管怎樣改變同一行中 p,q 的位置,真值表都是成立的。算法

1.3 異或運算規則

由上述的真值表,咱們能夠總結出如下異或運算的運算規則:編程

1 ⊕ 1 = 0
1 ⊕ 0 = 1
0 ⊕ 1 = 1
0 ⊕ 0 = 0

下面咱們以 8 ^ 6 爲例,來實際體驗一下異或運算。segmentfault

8 ^ 6 = 14
  0000 1000
^ 0000 0110
------------
  0000 1110

2、異或運算符性質

名稱 二進制表達式(8位)
p 15 0000 1111
q 8 0000 1000
r 6 0000 0110

2.1 交換律:p ⊕ q = q ⊕ p

p ⊕ q數組

0000 1111 //p=15
⊕ 0000 1000 //q=8
------------
  0000 0111

q ⊕ p編程語言

0000 1000 // q=8
⊕ 0000 1111 // p=15
------------
  0000 0111

2.2 結合律:p ⊕ (q ⊕ r) = (p ⊕ q) ⊕ r

p ⊕ (q ⊕ r)加密

0000 1000 //q=8
⊕ 0000 0110 //r=6
------------
  0000 1110 //(q ⊕ r)的結果
⊕ 0000 1111 //p=15
------------
  0000 0001 // p ⊕ (q ⊕ r)的結果

(p ⊕ q) ⊕ rspa

0000 1111 //p=15
⊕ 0000 1000 //q=8
------------
  0000 0111 //(p ⊕ q)的結果
⊕ 0000 0110 //r=6
------------
  0000 0001 // (p ⊕ q) ⊕ r的結果

2.3 恆等律:p ⊕ 0 = p

一個數與 0 進行異或運算等於它自己code

0000 1111 //p=15
⊕ 0000 0000
------------
  0000 1111

2.4 歸零律:p ⊕ p = 0

一個數與它自己進行異或運算等於 0

0000 1111 //p=15
⊕ 0000 1111 //p=15
------------
  0000 0000

基於該特性,能夠經過 a ⊕ b == 0 來判斷兩個整數的值是否相等。

2.5 自反:p ⊕ q ⊕ q = p ⊕ 0 = p

p ⊕ q ⊕ q

0000 1111 //p=15
⊕ 0000 1000 //q=8
------------
  0000 0111 //p ⊕ q的結果
⊕ 0000 1000 //q=8
------------
  0000 1111 // p ⊕ q ⊕ q的結果

3、異或運算符應用

3.1 使某些特定的位翻轉

給定整數 a,要求翻轉 a 對應二進制表達式中的特定位。假設整數 a 的值爲 10,其對應二進制表達式爲 0000 1010(以 8 位爲例),咱們要求對第 3 位和第 4 位進行翻轉,要實現這個需求,能夠將 a 與 b(12) 進行按位異或運算。

0000 1010 //a=10
⊕ 0000 1100 //b=12
------------
  0000 0110 //a ⊕ b的結果

經過觀察以上結果,咱們能夠發現第 3 位(0 -> 1)和第 4 位(1 -> 0)都完成了翻轉。

3.2 不用額外變量交換兩個整數的值

給定整數 a 和 b,不用額外變量交換兩個整數的值。針對該問題,能夠用如下三行代碼來交換 a 和 b 的值(a0 與 b0 表示原始值):

a = a ^ b; // ① a = a0 ^ b0,b = b0
b = a ^ b; // ② a = a0 ^ b0,b = a0 ^ b0 ^ b0 = a0
a = a ^ b; // ③ a = a0 ^ b0 ^ a0 = b0,b = a0

下面咱們來分析一下上述代碼的執行過程:

  • 執行完第一行代碼以後,a 的值變成 a0 ^ b0 的值,記爲 c,而 b 的值保持不變;
  • 執行完第二行代碼以後,a 的值不變仍爲 c,而 b 的值爲 c ^ b 即 a0 ^ b0 ^ b0 的運算結果,利用前面提到異或運算的特性能夠得出 b = a0 ^ (b0 ^ b0) = a0 ^ 0 = a0,即 b = a0;
  • 執行完第三行代碼以後,a 的值爲 a0 ^ b0 ^ a0 的運算結果,一樣利用異或運算的特性能夠得出 a = b0 ^ (a0 ^ a0) = b0 ^ 0,即 a = b0。

JavaScript Code:

function swap(a, b) {
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

3.3 只出現一次的數字

給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。異或運算符知足交換律和結合律,因此假設有一個非空整數數組爲:[A C B C B A D],把每一項進行異或運算:

A ^ C ^ B ^ C ^ B ^ A ^ D
 = A ^ A ^ B ^ B ^ C ^ C ^ D
 = 0 ^ 0 ^ 0 ^ D
 = 0 ^ D
 = D

JavaScript Code:

function singleNumber(nums) {
    let ans = 0;
    for(const num of nums) {
        ans ^= num;
    }
    return ans;
}

3.4 肯定將整數 A 轉換爲整數 B 所需翻轉的位數

給定兩個整數 A 和 B,請計算把整數 A 轉換爲整數 B 所需翻轉的位數。下面咱們來舉例說明一下:

名稱 十進制 二進制
A 15 0000 1111
B 10 0000 1010

經過觀察上述表格,要把整數 A(15)轉換成整數 B(10),須要翻轉的位數爲 2。這裏咱們再來回顧一下異或的運算規則:

1 ⊕ 1 = 0
1 ⊕ 0 = 1
0 ⊕ 1 = 1
0 ⊕ 0 = 0

而後咱們對整數 A 和整數 B 執行異或運算:

0000 1111
⊕ 0000 1010
------------
  0000 0101

這時咱們能夠知道,若是整數 A 和整數 B 對應位的值不一致的話,當前位的異或結果就爲 1,在轉換過程當中就須要進行翻轉。而要計算整數 A 轉換爲整數 B 所需翻轉的位數,就能夠轉換爲計算 A ⊕ B 運算結果二進制數中 1 的個數。

JavaScript Code:

function bitflip(a, b){
   let count = 0;
   let c = a ^ b;
   while(c != 0){
      c = c & (c - 1);
      count++;  
   }
   return count;
}

3.5 判斷一個二進制數中 1 的數量是奇數仍是偶數

給定一個二進制數如 0110 1100,求該二進制數中 1 的數量是奇數仍是偶數。利用異或運算 p ⊕ 0 = p 恆等律的特性,上述問題能夠這樣解答:0 ^ 1 ^ 1 ^ 0 ^ 1 ^ 1 ^ 0 ^ 0 = 0。若二進制數中每 1 位執行異或運算的結果爲 1,則 1 的數量是奇數,而結果爲 0,則 1 的數量是偶數。

該功能的實際應用場景是奇偶校驗,好比在串口通訊中,每一個字節的數據都計算一個校驗位,數據和校驗位一塊兒發送出去,這樣接收方能夠根據校驗位判斷接收到的數據是否有誤。

3.6 比特序列加密

現代的密碼都是創建在計算機的基礎上,這是由於現代的密碼所處理的數據量很是大,並且密碼算法也很是複雜,不借助計算機的力量就沒法完成加密和解密的操做。

計算機的操做對象並非文字,而是由 0 和 1 排列而成的比特序列。不管是文字、圖片、聲音、視頻仍是程序,在計算機中都是用比特序列來表示的。執行加密操做的程序,就是將表示明文的比特序列轉換爲表示密文的比特序列。

這裏咱們來看一個比特序列異或運算的示例:

0 1 0 0 1 1 0 0 // A
⊕ 1 0 1 0 1 0 1 0 // B 
--------------------
  1 1 1 0 0 1 1 0 //(A ⊕ B)的結果
⊕ 1 0 1 0 1 0 1 0 // B 
--------------------
  0 1 0 0 1 1 0 0 // A

可能你已經發現了,上面的計算過程和加密、解密的步驟很是類似。

  • 將明文 A 用密鑰 B 進行加密,獲得密文 A ⊕ B
  • 將密文 A ⊕ B 的結果異或密鑰 B 進行解密,獲得明文 A

實際上,只要選擇一個合適的 B,僅僅使用 XOR 就能夠實現一個高強度的密碼。

4、參考資源

本人的全棧修仙之路訂閱號,會按期分享 Angular、TypeScript、Node.js/Java 、Spring 相關文章,歡迎感興趣的小夥伴訂閱哈!

full-stack-logo

相關文章
相關標籤/搜索