定义:

格雷码(循环二进制单位距离码)是任意两个相邻数的代码只有一位二进制数不同的编码。
它与奇偶校验码同属可靠性编码。

简介:

格雷码(Gray code)是由贝尔实验室的Frank Gray在1940年提出,用于在PCM(脉冲编码调变)方法传送讯号时防止出错,并于1953年三月十七日取得美国专利。格雷码是一个数列集合,相邻两数间只有一个位元改变,为无权数码,且格雷码的顺序不是唯一的。

具体说明:

Gray Code是一个数列集合 ,每个数使用二进位来表示 ,假设使用n位元来表示每个数好了 ,任两个数之间只有一个位元值不同,
例如以下为3位元的Gray Code:
000 001 011 010 110 111 101 100

由定义可以知道,Gray Code的顺序并不是唯一的,例如将上面的数列反过来写,也是一组GrayCode:
100 101 111 110 010 011 001 000

代码原理及实现:

1.解法

由于Gray Code相邻两数之间只改变一个位元,所以可观 察Gray Code从1变0或从0变1时的位置,假设有4位元的Gray Code如下:
0000 0001 0011 0010 0110 0111 0101 1000
1100 1101 1111 1110 1010 1011 1001 1000
重点结论:
(1)观察奇数项的变化时,我们发现无论它是第几个Gray Code,(观察该奇数项的前一项偶数项并与其对比)永远只改变最右边的位元,如果是1就改为0,如果是0就改为1。
(2)观察偶数项的变化时,(观察该偶数项的前一项奇数项并与其对比)我们发现所改变的位元,是由右边算来第一个1的左边位元。
(3)枚举观察发现,随着位元个数的增大,该位元数下的格雷码的数量是2的(位元数)次幂。

以上两个变化规则是固定的,无论位元数为何;所以只要判断位元的位置是奇数还是偶数,就可以决定要改变哪一个位元的值,为了程式撰写方便,将阵列索引 0当作最右边的值,而在列印结果时,是由索引数字大的开始反向列印。
将2位元的Gray Code当作平面坐标来看,可以构成一个四边形,您可以发现从任一顶点出发,绕四边形周长绕一圈,所经过的顶点坐标就是一组Gray Code,所以您可以得到四组Gray Code。
同样的将3位元的Gray Code当作平面座标来看的话,可以构成一个正立方体,如果您可以从任一顶点出发,将所有的边长走过,并不重复经过顶点的话,所经过的顶点座标顺序之组合也就是一组Gray Code。

  1. 代码实现:
////格雷码的代码实现 
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
const int maxn = 30;
int bits;

int main () {
    cout << "输入位元数;";
    cin >> bits;
    getchar();
    char digit[maxn];
    memset(digit, '0', sizeof(char)*maxn);
    for (int j = 0; j < bits; j++) {
        digit[j] = '0';
    }
    digit[bits] = '\0';


    for (int j = 0; j < bits; j++) {
        cout << digit[j];
    }
    cout << endl;

    int i = 1;
    int time = (int)pow(2, bits);
    while (i < time) {  //(3)枚举观察发现,随着位元个数的增大,该位元数下的格雷码的数量是2的(位元数)次幂。
        //奇数项        //(1)观察奇数项的变化时,我们发现无论它是第几个Gray Code,(观察该奇数项的前一项偶数项并与其对比)永远只改变最右边的位元,如果是1就改为0,如果是0就改为1。
        if (i%2 == 1) {
            //只改变最右边的位元 
            digit[bits-1] = digit[bits-1] != '0' ? '0' : '1';
            //输出
            for (int j = 0; j < bits; j++) {
                cout << digit[j];
            }  
            cout << endl;
            i++;
        } 
        //偶数项        //(2)观察偶数项的变化时,(观察该偶数项的前一项奇数项并与其对比)我们发现所改变的位元,是由右边算来第一个1的左边位元。  
        else {  
            int k = bits-1;
            while (k >= 0) {
                if (digit[k] == '0') {
                    k--;
                }
                else {
                    break;
                }
            }
            digit[k-1] = digit[k-1] != '0' ? '0' : '1';
            //输出
            for (int j = 0; j < bits; j++) {
                cout << digit[j];
            }  
            cout << endl;
            i++;            
        }
    }
    return 0; 
} 

格雷码能避免讯号传送错误的原理:

传统的二进制系统例如数字3的表示法为011,要切换为邻近的数字4,也就是100时,装置中的三个位元都得要转换,因此于未完全转换的过程时装置会经历短暂的,010,001,101,110,111等其中数种状态,也就是代表着2、1、5、6、7,因此此种数字编码方法于邻近数字转换时有比较大的误差可能范围。格雷码的发明即是用来将误差之可能性缩减至最小,编码的方式定义为每个邻近数字都只相差一个位元,因此也称为最小差异码,可以使装置做数字步进时只更动最少的位元数以提高稳定性。

数字0~7的编码比较如下:

十进制 格雷码 二进制

0    000    000
1    001    001
2    011    010
3    010    011
4    110    100
5    111    101
6    101    110
7    100    111

格雷码的应用:

  • 格雷氏编码与相位移在三维曲面量测:利用格雷码投射在微型曲面做量测 一个非接触式、投影的方法光学测量。
  • 在化简逻辑函数时,可以通过按格雷码排列的卡诺图(数字电子技术课本(阎石第6版P40)来完成。
    图片说明
    图片说明
    图片说明
    图片说明
    图片说明
    图片说明

    和格雷码有相同数学模式的玩具:

    中国的古老益智玩具九连环有着和格雷码完全相同的数学模式,外国一款名为spin out的玩具也是运用相同的数学模式。

参考资料:
https://zh.wikipedia.org/wiki/%E6%A0%BC%E***7%E7%A0%81
https://blog.csdn.net/Helloyongwei/article/details/80178255
数字电子技术(阎石第6版)