在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不同,則稱這種編碼為格雷碼(Gray Code),另外由於最大數與最小數之間也僅一位數不同,即“首尾相連”,因此又稱循環碼或反射碼。在數字系統中,常要求代碼按一定順序變化。例如,按自然數遞增計數,若采用8421碼,則數0111變到1000時四位均要變化,而在實際電路中,4位的變化不可能絕對同時發生,則計數中可能出現短暫的其它代碼(1100、1111等)。在特定情況下可能導致電路狀態錯誤或輸入錯誤。使用格雷碼可以避免這種錯誤。格雷碼有多種編碼形式。
格雷碼有多種編碼形式
十進制數 | 4位自然二進制碼 | 4位典型格雷碼 |
十進制余三格雷碼
|
十進制空六格雷碼 | 十進制跳六格雷碼 | 步進碼 |
---|---|---|---|---|---|---|
0
|
0000
|
0000
|
0010
|
0000
|
0000
|
00000
|
1
|
0001
|
0001
|
0110
|
0001
|
0001
|
00001
|
2
|
0010
|
0011
|
0111
|
0011
|
0011
|
00011
|
3
|
0011
|
0010
|
0101
|
0010
|
0010
|
00111
|
4
|
0100
|
0110
|
0100
|
0110
|
0110
|
01111
|
5
|
0101
|
0111
|
1100
|
1110
|
0111
|
11111
|
6
|
0110
|
0101
|
1101
|
1010
|
0101
|
11110
|
7
|
0111
|
0100
|
1111
|
1011
|
0100
|
11100
|
8
|
1000
|
1100
|
1110
|
1001
|
1100
|
11000
|
9
|
1001
|
1101
|
1010
|
1000
|
1000
|
10000
|
10
|
1010
|
1111
|
----
|
----
|
----
|
----
|
11
|
1011
|
1110
|
----
|
----
|
----
|
----
|
12
|
1100
|
1010
|
----
|
----
|
----
|
----
|
13
|
1101
|
1011
|
----
|
----
|
----
|
----
|
14
|
1110
|
1001
|
----
|
----
|
----
|
----
|
15
|
1111
|
1000
|
---- | ---- | ---- | ---- |
表中典型格雷碼具有代表性。若不作特別說明,格雷碼就是指典型格雷碼,它可從自然二進制碼轉換而來。
轉換方法
遞歸生成碼表
這種方法基於格雷碼是反射碼的事實,利用遞歸的如下規則來構造:
-
1位格雷碼有兩個碼字
-
(n+1)位格雷碼中的前2 n個碼字等於n位格雷碼的碼字,按順序書寫,加前綴0
-
(n+1)位格雷碼中的后2n個碼字等於n位格雷碼的碼字,按逆序書寫,加前綴1
-
n+1位格雷碼的集合 = n位格雷碼集合(順序)加前綴0 + n位格雷碼集合(逆序)加前綴1
2位格雷碼 | 3位格雷碼 | 4位格雷碼 | 4位自然二進制碼 |
---|---|---|---|
00
01
11
10
|
000
001
011
010
110
111
101
100
|
0000
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000
|
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
|
異或轉換
二進制碼→格雷碼(編碼):
此方法從對應的n位二進制碼字中直接得到n位格雷碼碼字,步驟如下:
-
對n位二進制的碼字,從右到左,以0到n-1編號
-
如果二進制碼字的第i位和i+1位相同,則對應的格雷碼的第i位為0,否則為1(當i+1=n時,二進制碼字的第n位被認為是0,即第n-1位不變)
例如:二進制碼0101,為4位數,所以其所轉為之格雷碼也必為4位數,因此可取轉成之二進位碼第五位為0,即0 b3 b2 b1 b0。
0 xor 0=0,所以g3=0
0 xor 1=1,所以g2=1
1 xor 0=1,所以g1=1
0 xor 1=1,所以g0=1
因此所轉換為之格雷碼為0111
|
其實,從上述格雷碼異或轉換的方法可以得到一個簡單易行的算法,例如,對於一個2進制比特不超過32位的整數x,它的格雷碼即可表示為 (x>>1)^x。
算法演示:
#include <stdio.h> #include <stdlib.h> void print_bin(unsigned int value,char *tail); //打印一個數字的bit位 int main(int argc,char* argv[]) { unsigned int temp; for(unsigned int i=0;i<=15;i++) { printf("%-4d:",i); temp=(i>>1)^i; //轉換代碼僅僅一行,很簡單 print_bin(temp,"\n"); } return 0; } void print_bin(unsigned int value,char* tail) { for(int i=31;i>=0;i--) { printf("%d",(value>>i)&1); } if(tail) { printf("%s",tail); } }
編譯運行結果:
root@javis:~/Documents/Code$ gcc test.c -std=c99 -o test.out root@javis:~/Documents/Code$ ./test.out 0 :00000000000000000000000000000000 1 :00000000000000000000000000000001 2 :00000000000000000000000000000011 3 :00000000000000000000000000000010 4 :00000000000000000000000000000110 5 :00000000000000000000000000000111 6 :00000000000000000000000000000101 7 :00000000000000000000000000000100 8 :00000000000000000000000000001100 9 :00000000000000000000000000001101 10 :00000000000000000000000000001111 11 :00000000000000000000000000001110 12 :00000000000000000000000000001010 13 :00000000000000000000000000001011 14 :00000000000000000000000000001001 15 :00000000000000000000000000001000