在數字邏輯中,邏輯算符異或(exclusive or
)是對兩個運算元的一種邏輯分析類型,符號爲 XOR 或 ⊕(編程語言中經常使用 ^
)。但與通常的邏輯或不一樣,異或算符的值爲真僅當兩個運算元中恰有一個的值爲真,而另一個的值爲非真。javascript
名稱 | 符號 |
---|---|
數學符號 | ⊕ |
英文簡稱 | xor |
程序符號 | ^ |
異或運算 p ⊕ q 的真值表以下:java
p | q | ⊕ |
---|---|---|
T | T | F |
T | F | T |
F | T | T |
F | F | F |
不管怎樣改變同一行中 p,q 的位置,真值表都是成立的。算法
由上述的真值表,咱們能夠總結出如下異或運算的運算規則:編程
1 ⊕ 1 = 0 1 ⊕ 0 = 1 0 ⊕ 1 = 1 0 ⊕ 0 = 0
下面咱們以 8 ^ 6 爲例,來實際體驗一下異或運算。segmentfault
8 ^ 6 = 14 0000 1000 ^ 0000 0110 ------------ 0000 1110
名稱 | 值 | 二進制表達式(8位) |
---|---|---|
p | 15 | 0000 1111 |
q | 8 | 0000 1000 |
r | 6 | 0000 0110 |
p ⊕ q數組
0000 1111 //p=15 ⊕ 0000 1000 //q=8 ------------ 0000 0111
q ⊕ p編程語言
0000 1000 // q=8 ⊕ 0000 1111 // p=15 ------------ 0000 0111
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的結果
一個數與 0 進行異或運算等於它自己code
0000 1111 //p=15 ⊕ 0000 0000 ------------ 0000 1111
一個數與它自己進行異或運算等於 0
0000 1111 //p=15 ⊕ 0000 1111 //p=15 ------------ 0000 0000
基於該特性,能夠經過 a ⊕ b == 0
來判斷兩個整數的值是否相等。
p ⊕ q ⊕ q
0000 1111 //p=15 ⊕ 0000 1000 //q=8 ------------ 0000 0111 //p ⊕ q的結果 ⊕ 0000 1000 //q=8 ------------ 0000 1111 // p ⊕ q ⊕ q的結果
給定整數 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)都完成了翻轉。
給定整數 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
下面咱們來分析一下上述代碼的執行過程:
b = a0 ^ (b0 ^ b0) = a0 ^ 0 = a0
,即 b = a0;a = b0 ^ (a0 ^ a0) = b0 ^ 0
,即 a = b0。JavaScript Code:
function swap(a, b) { a = a ^ b; b = a ^ b; a = a ^ b; }
給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。異或運算符知足交換律和結合律,因此假設有一個非空整數數組爲:[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; }
給定兩個整數 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; }
給定一個二進制數如 0110 1100
,求該二進制數中 1 的數量是奇數仍是偶數。利用異或運算 p ⊕ 0 = p 恆等律的特性,上述問題能夠這樣解答:0 ^ 1 ^ 1 ^ 0 ^ 1 ^ 1 ^ 0 ^ 0 = 0
。若二進制數中每 1 位執行異或運算的結果爲 1,則 1 的數量是奇數,而結果爲 0,則 1 的數量是偶數。
該功能的實際應用場景是奇偶校驗,好比在串口通訊中,每一個字節的數據都計算一個校驗位,數據和校驗位一塊兒發送出去,這樣接收方能夠根據校驗位判斷接收到的數據是否有誤。
現代的密碼都是創建在計算機的基礎上,這是由於現代的密碼所處理的數據量很是大,並且密碼算法也很是複雜,不借助計算機的力量就沒法完成加密和解密的操做。
計算機的操做對象並非文字,而是由 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
可能你已經發現了,上面的計算過程和加密、解密的步驟很是類似。
實際上,只要選擇一個合適的 B,僅僅使用 XOR 就能夠實現一個高強度的密碼。
本人的全棧修仙之路訂閱號,會按期分享 Angular、TypeScript、Node.js/Java 、Spring 相關文章,歡迎感興趣的小夥伴訂閱哈!