格雷码生成算法分析及实现(C/OC)

来源:互联网 发布:公安数据恢复 编辑:程序博客网 时间:2024/06/03 17:21

格雷码简介

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

000001 011 010 110 111 101 100

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

100101 111 110 010 011 001 000

Gray Code是由贝尔实验室的Frank Gray在1940年代提出的,用来在使用PCM(PusleCode Modulation)方法传送讯号时避免出错,并于1953年三月十七日取得美国专利。

格雷码优缺点

格雷码属于可靠性编码,是一种错误最小化的编码方式。因为,虽然自然二进制码可以直接由数/模转换器转换成模拟信号,但在某些情况,例如从十进制的3转换为4时二进制码的每一位都要变,能使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它在相邻位间转换时,只有一位产生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。由于这种编码相邻的两个码组之间只有一位不同,因而在用于风向的转角位移量-数字量的转换中,当风向的转角位移量发生微小变化(而可能引起数字量发生变化时,格雷码仅改变一位,这样与其它编码同时改变两位或多位的情况相比更为可靠,即可减少出错的可能性。例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,4位的变化不可能绝对同时发生,则计数中可能出现短暂的其它代码(1100、1111等)。在特定情况下可能导致电路状态错误或输入错误。使用格雷码可以避免这种错误。
格雷码是一种绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。
由于格雷码是一种变权码,每一位码没有固定的大小,很难直接进行比较大小和算术运算,也不能直接转换成液位信号,要经过一次码变换,变成自然二进制码,再由上位机读取。[3]
典型格雷码是一种采用绝对编码方式的准权码,其权的绝对值为2^i-1(设最低位i=1)。
格雷码的十进制数奇偶性与其码字中1的个数的奇偶性相同。

格雷码生成算法分析

 由于GrayCode相邻两数之间只改变一个位元,所以可观 察GrayCode从1变0或从0变1时的位置,假设有4位元的GrayCode如下:

0000 0001 0011 0010 0110 0111 0101 0100

1100 1101 1111 1110 1010 1011 1001 1000

观察奇数项的变化时,我们发现无论它是第几个Gray Code,永远只改变最右边的位元,如果是1就改为0,如果是0就改为1。

观察偶数项的变化时,我们发现所改变的位元,是由右边算来第一个1的左边位元。

以上两个变化规则是固定的,无论位元数为何;所以只要判断位元的位置是奇数还是偶数,就可以决定要改变哪一个位元的值,为了程式撰写方便,将阵列索引 0当作最右边的值,而在列印结果时,是由索引数字大的开始反向列印。

将2位元的Gray Code当作平面座标来看,可以构成一个四边形,您可以发现从任一顶点出发,绕四边形周长绕一圈,所经过的顶点座标就是一组Gray Code,所以您可以得到四组Gray Code。

同样的将3位元的Gray Code当作平面座标来看的话,可以构成一个正立方体,如果您可以从任一顶点出发,将所有的边长走过,并不重复经过顶点的话,所经过的顶点座标顺序之组合也就是一组Gray Code。

代码实现(C/OC)

#define MAXBIT 20//字符数组大小#define TRUE 1#define CHANGE_BIT(x) x = ((x) == '0' ? '1' : '0')//取反#define NEXT(x) x = (1 - (x))//改变奇偶

//主程序,不清楚的可参考注释char digit[MAXBIT];//声明字符数组int i;//循环的时候用int bits;//位元数,只是一个数字int odd;//是不是奇数(不断在奇偶间变化)    int dNum = 0;//十进制中对应的数字printf("%d  ",dNum);dNum++;bits = 4;//位元数,这里以4为例for(i = 0; i < bits; i++) {//初始化,全部为0    digit[i] = '0';    printf("0");}printf("\n");odd = TRUE;//是奇数,以上是为了输出0所对应的格雷码,特殊处理,顺便初始化字符数组while(1) {//没结束,就循环下去吧    if(odd)        CHANGE_BIT(digit[0]);//第一位直接取反    else {        for(i = 0; i < bits && digit[i] == '0'; i++) ;//计算第一个1的位置        if(i == bits - 1) //最后一个Gray Code,跳出循环            break;        CHANGE_BIT(digit[i+1]);//偶数,没有结束,改变    }    printf("%d  ",dNum);    dNum++;    for(i = bits - 1; i >= 0; i--)//反向打印        printf("%c", digit[i]);        printf("\n");    NEXT(odd);//改变奇偶}






0 0