定义:
格雷码(循环二进制单位距离码)是任意两个相邻数的代码只有一位二进制数不同的编码。
它与奇偶校验码同属可靠性编码。
简介:
格雷码(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。
- 代码实现:
////格雷码的代码实现 #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版)