标题：格雷码
基本简介
[1]因为，自然二进制码可以直接由数/模转换器转换成模拟信号，但某些情况，例如从十进制的3转换到4时二进制码的每一位都要变，使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点，它是一种数字排序系统，其中的所有相邻整数在它们的数字表示中只有一个数字不同。它在任意两个相邻的数之间转换时，只有一个数位发生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。另外由于最大数与最小数之间也仅一个数不同，故通常又叫格雷反射码或循环码。
数学性质
⒈ 典型格雷码是一种采用绝对编码方式的准权码，其权的绝对值为2^i-1(设最低位i=1)。
⒉ 格雷码的整数奇偶性与其1数奇偶性相同。
对照表
下表为几种自然二进制码与格雷码的对照表：
十进制数
自然二进制数
格雷码
0
0000
0000
1
0001
0001
2
0010
0011
3
0011
0010
4
0100
0110
5
0101
0111
6
0110
0101
7
0111
0100
8
1000
1100
9
1001
1101
10
1010
1111
11
1011
1110
12
1100
1010
13
1101
1011
14
1110
1001
15
1111
1000
一般的，普通二进制码与格雷码可以按以下方法互相转换：
二进制码->格雷码（编码）：从最右边一位起，依次将每一位与左边一位异或（XOR），作为对应格雷码该位的值，最左边一位不变（相当于左边是0）；
格雷码-〉二进制码（解码）：从左边第二位起，将每位与左边一位解码后的值异或，作为该位解码后的值（最左边一位依然不变）。
数学（计算机）描述：
原码：p[n:0]；格雷码：c[n:0](n∈N）；编码：c=G(p）；解码：p=F(c）；
书写时按从左向右标号依次减小，即MSB->LSB，编解码也按此顺序进行
编码：
...................c[n]=p[n]，
...................c[i]=p[i] XOR p[i+1](i∈N,n-1≥i≥0)；
解码：
...................p[n]=c[n]，
...................P[i]=c[i] XOR p[i+1](i∈N,n-1≥i≥0）。
Gray Code的编码方式不是唯一的，这里讨论的是最常用的一种。
互换
如果在二进制运算中忽略进位、退位，那么加减运算都变成了异或（XOR）。
用异或代替加减进行二进制竖式乘除，称为异或乘除，它的特点是无进退位。
由于没有退位，异或除法将变得更像多项式除法。
如：10101除以11将变成1100余1，而不是111。
二进制转格雷码：
只要异或乘以二分之三，即二进制的1.1，然后忽略小数部分；也可以理解成异或乘以三（即11），再右移一位。
格雷码转二进制：
异或乘以三分之二，即除以1.1，忽略余数；或者左移一位，再异或除以三，忽略余数。
发展历史
格雷码（Gray Code）因Frank Gray 1947年申请、1953年获得批准的专利“Pulse Code Communication”而得名，当初是为了通信，现在则常用于模拟－数字转换中。法国工程师Jean-Maurice-&Eacute;mlle Baudot在1880年曾用过的波特码是典型格雷码的一种变形。1941年George Stibitz设计过一种8元格雷码计数器。格雷码（Gray Code）曾用过Grey Code、葛莱码、格莱码、戈莱码、循环码、反射二进制码、最小差错码等名字，它们有的不对，有的易与其它名称混淆，建议不要再使用这些曾用名。
格雷码是一种绝对编码方式，典型格雷码是一种具有反射特性和循环特性的单步自补码，它的循环、单步特性消除了随机取数时出现重大误差的可能，它的反射、自补特性使得求反非常方便。格雷码属于可靠性编码，是一种错误最小化的编码方式，因为，虽然自然二进制码可以直接由数/模转换器转换成模拟信号，但在某些情况，例如从十进制的3转换为4时二进制码的每一位都要变，能使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点，它在相邻位间转换时，只有一位产生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。由于这种编码相邻的两个码组之间只有一位不同，因而在用于风向的转角位移量－数字量的转换中，当风向的转角位移量发生微小变化（而可能引起数字量发生变化时，格雷码仅改变一位，这样与其它编码同时改变两位或多位的情况相比更为可靠，即可减少出错的可能性。
由于格雷码是一种变权码，每一位码没有固定的大小，很难直接进行比较大小和算术运算，也不能直接转换成液位信号，要经过一次码变换，变成自然二进制码，再由上位机读取。解码的方法是用‘0’和采集来的4位格雷码的最高位（第4位）异或，结果保留到4位，再将异或的值和下一位（第3位）相异或，结果保留到3位，再将相异或的值和下一位（第2位）异或，结果保留到2位，依次异或，直到最低位，依次异或转换后的值（二进制数）就是格雷码转换后自然码的值. 
异或：异或则是按位“异或”，相同为“0”，相异为“1”。例：
10011000 异或 01100001 结果： 11111001 
举例： 
如果采集器器采到了格雷码：1010 
就要将它变为自然二进制： 
0 与第四位 1 进行异或结果为 1 
上面结果1与第三位0异或结果为 1 
上面结果1与第二位1异或结果为 0 
上面结果0与第一位0异或结果为 0 
因此最终结果为：1100 这就是二进制码即十进制 12 
当然人看时只需对照表1一下子就知道是12
格雷码解码的Pascal 程序：
var x,y,i:longint;
begin
readln(x);
for i:= 30 downto 0 do
begin
y:=(x and (1 shl i )) xor (( x and (1 shl(i+1))) shr 1);
x:=x and not (1 shl i ) or y;
end;
writeln(x);
end.
2 
var
x,i,n:longint;
begin
readln(n);
x:=n;
for i:=1 to 31 do
begin
x:=x shr 1;
n:=n xor x;
end;
writeln(n);
end.
转换方法
（假设以二进制为0的值做为格雷码的0）
G：格雷码 B：二进位码
G(N) = B(n+1) XOR B(n)
  
2位元格雷码
00
01
11
10
3位元格雷码
000
001
011
010
110
111
101
100
4位元格雷码 
0000
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000
4位元2进位原始码 
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
  
卡诺图
编写格雷码
二位格雷码
AB
0
1
0
0→
1↓
1
2
←3
顺序0 1 3 2 （对应的十进制）
00 起点
01
11
10终点
三位格雷码（三位格雷码由建立在二位基础上）
AB╲ C
0
1
00
0→
1↓
01
↓2
←3
11
6→
7↓
10
4
←5
顺序0 1 3 2 6 7 5 4 （对应的十进制）
000 起点
001
011
010
110
111
101
100终点
四位格雷码
AB╲CD
00
01
11
10
00
0→
1→
3→
2↓
01
↓4
←5
←7
←6
11
12→
13→
15→
14↓
10
8
←9
←11
←10
顺序0 1 3 2 6 7 5 4 12 13 15 14 10 11 9 8 （对应的十进制）
0000起点
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000终点
五位格雷码
ABC╲DE
00
01
11
10
000 
起点
→
→
↓
001
↓
←
←
←
011
→
→
→
↓
010
↓
←
←
←
110
→
→
→
↓
111
↓
←
←
←
101
→
→
→
↓
100
终点
←
←
←
规律性的往下写
N 位格雷码........
二进位数
二进位码第n位 = 二进位码第（n+1）位时异或格雷码第n位。因为二进位码和格雷码皆有相同位数，所以二进位码可从最高位的左边位元取0，以进行计算。
例如：格雷码0111，为4位数，所以其所转为之二进位码也必为4位数，因此可取转成之二进位码第五位为0，即0 b3 b2 b1 b0。
0 xor 0=0，所以b3=0
0 xor 1=1，所以b2=1
1 xor 1=0，所以b1=0
0 xor 1=1，所以b0=1
因此所转换为之二进位码为0101
C源码
根据格雷码的特点，即：对于两个相邻的十进制数，对应的两个格雷码只有一个二进制位不同。另外，最大数与最小数间也仅有一个二进制位不同。以下给出用长度n的二进制数来表示十进制数m的格雷码c实现，运行结果如右图所示：  十进制数的格雷码[2]---------------------------------c源码实现---------------------------------
[3]#include<stdio.h>
void main(){
int m,n,i,j,b,p,bound;
int gr[14];
//输入n,m并判断m是否合法
bound=1;
printf("Please input two number:n,m\n");
scanf("%d,%d",&n,&m);
for(i=1;i<=n;i++)
bound*=2;
if(m<0||m>=bound)
{
printf("Data error!");
exit(0);
}
b=1;
for(i=0;i<n;i++){
p=0;
b*=2;
for(j=0;j<=m;j++){
if(j%b-b/2==0)
p=1-p;
}
gr[i]=p;
}
printf("m=");
for(i=n-1;i>=0;i--){
printf("%d",gr[i]);
}
printf("\n");
}
---------------------------------c源码实现---------------------------------