算法學習(6)----整數轉換為格雷碼


  在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不同,則稱這種編碼為格雷碼(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. 1位格雷碼有兩個碼字
  2. (n+1)位格雷碼中的前2 n個碼字等於n位格雷碼的碼字,按順序書寫,加前綴0
  3. (n+1)位格雷碼中的后2n個碼字等於n位格雷碼的碼字,按逆序書寫,加前綴1
  4. 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位格雷碼碼字,步驟如下:
  1. 對n位二進制的碼字,從右到左,以0到n-1編號
  2. 如果二進制碼字的第i位和i+1位相同,則對應的格雷碼的第i位為0,否則為1(當i+1=n時,二進制碼字的第n位被認為是0,即第n-1位不變)
公式表示:
   
(G:格雷碼,B:二進制碼)
例如:二進制碼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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM