格雷码Gray Code详解
格雷码简介
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。格雷码(Gray Code)又称Grey Code、葛莱码、格莱码、戈莱码、循环码、反射二进制码、最小差错码等。
格雷码有多种编码形式
十进制数 | 4位自然二进制码 | 4位典型格雷码 |
十进制余三格雷码
|
十进制空六格雷码 | 十进制跳六格雷码 | 步进码 |
---|---|---|---|---|---|---|
0
|
0000
|
0000
|
0010
|
0000
|
0000
|
00000
|
1
|
0001
|
0001
|
0110
|
0001
|
0001
|
00001
|
2
|
0010
|
0011
|
0111
|
0011
|
0011
|
00011
|
...
为什么要使用格雷码?
格雷码是一种具有反射特性和循环特性的单步自补码,其循环和单步特性消除了随机取数时出现重大错误的可能,其反射和自补特性使得对其进行求反操作也非常方便,所以,格雷码属于一种可靠性编码,是一种错误最小化的编码方式,因此格雷码在通信和测量技术中得到广泛应用。
格雷码属于可靠性编码,是一种错误最小化的编码方式。因为,虽然自然二进制码可以直接由数/模转换器转换成模拟信号,但在某些情况,例如从十进制的3转换为4时二进制码的每一位都要变,能使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它在相邻位间转换时,只有一位产生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。由于这种编码相邻的两个码组之间只有一位不同,因而在用于方向的转角位移量-数字量的转换中,当方向的转角位移量发生微小变化(而可能引起数字量发生变化时,格雷码仅改变一位,这样与其它编码同时改变两位或多位的情况相比更为可靠,即可减少出错的可能性。
在数字系统中,常要求代码按一定顺序变化。例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,4位的变化不可能绝对同时发生,则计数中可能出现短暂的其它代码(1100、1111等)。在特定情况下可能导致电路状态错误或输入错误。使用格雷码可以避免这种错误。
格雷码是一种绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。
由于格雷码是一种变权码,每一位码没有固定的大小,很难直接进行比较大小和算术运算,也不能直接转换成液位信号,要经过一次码变换,变成自然二进制码,再由上位机读取。
典型格雷码是一种采用绝对编码方式的准权码,其权的绝对值为2^i-1(设最低位i=1)。
格雷码的十进制数奇偶性与其码字中1的个数的奇偶性相同。
应用
格雷氏编码与相位移在三维曲面量测:利用格雷码投射在微型曲面做量测 一个非接触式、投影的方法光学测量。
在化简逻辑函数时,可以通过按格雷码排列的卡诺图来完成。
角度传感器:汽车制动系统有时需要传感器产生的数字值来指示机械位置。如图是编码盘和一些触点的概念图,根据盘转的位置,触点产生一个3位二进制编码,共有8个这样的编码。盘中暗的区域与对应的逻辑1的信号源相连;亮的区域没有连接,触点将其解释为逻辑0。使用格雷码对编码盘上的亮暗区域编码,使得其连续的码字之间只有一个数位变化。这样就不会因为器件制造的精确度有限,而使得触点转到边界位置而出现错误编码。
九连环问题:中国的古老益智玩具九连环有着和格雷码完全相同的数学模式,外国一款名为spin out的玩具也是运用相同的数学模式。智力玩具九连环的状态 变化符合格雷码的编码规律,汉诺塔的解法也与格雷码有关。九连环中的每个环都有上下两种状态,如果把这两种状态用0/1来表示的话,这个状态序列就会形成一种循环二进制编码(格雷码)的序列。所以解决九连环问题所需要的状态变化数就是格雷码111111111所对应的十进制数341。
二进制格雷码的生成
直接排列
生成二进制格雷码方式1:以二进制为0值的格雷码为第零项,第一项改变最右边的位元,第二项改变右起第一个为1的位元的左边位元,第三、四项方法同第一、二项,如此反复,即可排列出n个位元的格雷码。
镜射排列
生成二进制格雷码方式2:n位元的格雷码可以从n-1位元的格雷码以上下镜射后加上新位元的方式快速的得到,如图所示。
000
001
011
010
110
111
101
100
[格雷码维基百科]
其它方法
利用卡诺图生成
- 将卡诺图变量分为两组,变量数目相近(最好相等)
- 以逻辑变量高位在左低位在右建立卡诺图
- 从卡诺图的左上角以之字形到右上角最后到左下角遍历卡诺图,依次经过格子的变量取值即为典型格雷码的顺序
[百度百科 格雷码]
利用二进制码转换
转换方法参考下面吧。
格雷码和二进制码的转换
自然二进制码与格雷码的对照表:
十进制数 | 自然二进制数 | 格雷码 | 十进制数 | 自然二进制数 | 格雷码 |
0 | 0000 | 0000 | 8 | 1000 | 1100 |
1 | 0001 | 0001 | 9 | 1001 | 1101 |
2 | 0010 | 0011 | 10 | 1010 | 1111 |
3 | 0011 | 0010 | 11 | 1011 | 1110 |
4 | 0100 | 0110 | 12 | 1100 | 1010 |
5 | 0101 | 0111 | 13 | 1101 | 1011 |
6 | 0110 | 0101 | 14 | 1110 | 1001 |
7 | 0111 | 0100 | 15 | 1111 | 1000 |
二进制码转换成二进制格雷码
二进制码转换成二进制格雷码,其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。
二进制码 ----> 格雷码(编码):从最右边一位起,依次将每一位与左边一位异或(XOR),作为对应格雷码该位的值,最左边一位不变(相当于左边是0)。
Note: 这样做可行的原因,是因为二进制码每次+1时最多只有一个相邻的两个bit对的异或值会发生改变。
公式表示:G:格雷码 B:二进制码
整个数G(N) = (B(n) >> 1) XOR B(n)
格雷码转换成二进制码
二进制格雷码转换成二进制码,其法则是保留格雷码的最高位作为自然二进制码的最高位,而次高位自然二进制码为高位自然二进制码与次高位格雷码相异或,而自然二进制码的其余各位与次高位自然二进制码的求法相类似。
公式表示:
格雷码转换为二进制码算法有以下几种表述形式:
表述一:
二进制格雷码为Gn-1Gn-2...G2G1G0
自然二进制码为Bn -1Bn-2...B2B1B0
其中:最高位保留 Bn-1=Gn-1
其他各位 Bi-1=Gi-1 xor Bi ,i=1,2,...,n-1
表述二:
Bi = ˆG[n-1:i]=G[n-1]ˆG[n-2]ˆ..ˆG[i],i=0,1,...,n-1
表述三:
Bi = ˆ(G>>i),i=0,1,...,n-1
[格雷码(Gray Code)转二进制码(Binary Code)]
二进制格雷码字符串生成
c++ stl递归和非递归代码
vector<string> gray0(int n) {
/*
* 格雷码字符串的直接排列递归实现
* 思路:1、获得n-1位生成格雷码的数组
* 2、由于n位生成的格雷码位数是n-1的两倍,故只要在n为格雷码的前半部分加0,后半部分加1即可。
*/
if (n == 0)
return vector<string>{"0"};
else if (n == 1) {
return vector<string>({"0", "1"});
} else {
vector<string> new_gray_code;
vector<string> gray_code = gray0(n - 1);
// vector<string> gray_code = vector<string>({"0", "1"}); vector<string>::iterator gc_it;
for (gc_it = gray_code.begin(); gc_it != gray_code.end(); gc_it++)
new_gray_code.push_back("0" + *gc_it); vector<string>::reverse_iterator gc_rit;
for (gc_rit = gray_code.rbegin(); gc_rit != gray_code.rend(); gc_rit++)
new_gray_code.push_back("1" + *gc_rit);
return new_gray_code;
}
} vector<string> gray1(int n) {
/*
* 格雷码字符串的镜射排列非递归实现
*/
if (n == 0)
return vector<string>{"0"}; vector<string> gray_code = vector<string>({"0", "1"});
while (--n) {
vector<string> new_gray_code; vector<string>::iterator gc_it;
for (gc_it = gray_code.begin(); gc_it != gray_code.end(); gc_it++)
new_gray_code.push_back("0" + *gc_it); vector<string>::reverse_iterator gc_rit;
for (gc_rit = gray_code.rbegin(); gc_rit != gray_code.rend(); gc_rit++)
new_gray_code.push_back("1" + *gc_rit); gray_code = new_gray_code;
}
return gray_code;
}
非stl c++代码[格雷码那点事——递归非递归实现][格雷码的实现]
public void getGrayCode(int bitNum){
for(int i = 0; i < (int)Math.pow(2, bitNum); i++){
int grayCode = (i >> 1) ^ i;
System.out.println(num2Binary(grayCode, bitNum));
}
}
public String num2Binary(int num, int bitNum){
String ret = "";
for(int i = bitNum-1; i >= 0; i--){
ret += (num >> i) & 1;
}
return ret;
}
格雷码Gray Code详解的更多相关文章
- 格雷码(Gray code)仿真
作者:桂. 时间:2018-05-12 16:25:02 链接:http://www.cnblogs.com/xingshansi/p/9029081.html 前言 FIFO中的计数用的是格雷码, ...
- Android源码下载方法详解
转自:http://www.cnblogs.com/anakin/archive/2011/12/20/2295276.html Android源码下载方法详解 相信很多下载过内核的人都对这个很熟悉 ...
- ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...
- [Spark內核] 第41课:Checkpoint彻底解密:Checkpoint的运行原理和源码实现彻底详解
本课主题 Checkpoint 运行原理图 Checkpoint 源码解析 引言 Checkpoint 到底是什么和需要用 Checkpoint 解决什么问题: Spark 在生产环境下经常会面临 T ...
- 【Java】HashMap源码分析——常用方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...
- 【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量—— ...
- Spring Boot源码中模块详解
Spring Boot源码中模块详解 一.源码 spring boot2.1版本源码地址:https://github.com/spring-projects/spring-boot/tree/2.1 ...
- React源码 commit阶段详解
转: React源码 commit阶段详解 点击进入React源码调试仓库. 当render阶段完成后,意味着在内存中构建的workInProgress树所有更新工作已经完成,这包括树中fiber节点 ...
- 《阿里巴巴Java开发手册》码出高效详解(一)- 为什么要学习阿里编码手册
<Java 开发手册>(以下简称<手册>)是每个 Java 工程师人手必备的一本参考指南.该手册包括 编程规约.异常日志.单元测试.安全规约.MySQL 数据库.工程结构.设计 ...
随机推荐
- PHP面向对象编程一
php面向对象编程(一) 类与对象关系: 类就像一个人类的群体 我们从类中实例化一个对象 就像是制定一个人. 面向对象程序的单位就是对象,但对象又是通过类的实例化出来的,所以我们首先要做的就是如何 ...
- EditPlus常用操作
EditPlus注册码在线生成 http://www.jb51.net/tools/editplus/ 随意填写个用户名,生成对应的密码就可以使用editplus了 EditPlus常用快捷键 编代码 ...
- C#获得字符串首字符字母(大写)
/// <summary> /// 获得字符串首字符字母(大写): /// </summary> /// <param name="cnChar"&g ...
- DockerSwarm 微服务部署
一.简介 之前<服务Docker化>中,使用 docker-compose.yml 来一次配置启动多个容器,在 Swarm 集群中也可以使用 compose 文件 (docker-comp ...
- 面向对象设计与构造:oo课程总结
面向对象设计与构造:OO课程总结 第一部分:UML单元架构设计 第一次作业 UML图 MyUmlInteraction类实现接口方法,ClassUnit和InterfaceUnit管理UML图中的类和 ...
- hibernate课程 初探单表映射1-4 hibernate开发前准备
开发前准备: 1 eclipse 2 hibernate tools的安装(需要相关的jar包)(可以简化orm框架) hibernate tools的安装步骤: 1 到官网下载 https://so ...
- jeesite应用实战(数据增删改查),认真读完后10分钟就能开发一个模块
jeesite配置指南(官方文档有坑,我把坑填了!)这篇文章里,我主要把jeesite官方给出的帮助文档的坑填了,按照里面的方法可以搭建起来jeesite的站点.系统可以运行以后,就可以进入开发模块了 ...
- 巧用netsh命令实现端口转发(端口映射)不求人
好处:即时生效,随意修改删除,不影响其他ip映射 记事本保存为bat格式批量添加后,并查看映射: netsh interface portproxy add v4tov4 listenport=701 ...
- Jsoup查找dom元素
package com.open1111.jsoup; import org.apache.http.HttpEntity;import org.apache.http.client.methods. ...
- COGS 1043. [Clover S2] Freda的迷宫
★ 输入文件:mazea.in 输出文件:mazea.out 简单对比时间限制:1 s 内存限制:128 MB Freda 的迷宫 (mazea.pas/.c/.cpp) 题目叙述 F ...