打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
格雷码简介及格雷码与二进制的转换程序

格雷码简介及格雷码与二进制的转换程序

格雷码简介及格雷码与二进制的转换程序

格雷码简介

  格雷码(英文:Gray Code, Grey Code,又称作葛莱码,二进制循环码)是1880年由法国工程师Jean-Maurice-Emlle
Baudot发明的一种编码[1] ,因Frank Gray于1953年申请专利“Pulse Code
Communication”得名。当初是为了机械应用,后来在电报上取得了巨大发展[2],现在则常用于模拟-数字转换[3]和转角-数字转换中[4] 。
  典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便[5] 。
  格雷码属于可靠性编码,是一种错误最小化的编码,因为它大大地减少了由一个状态到下一个状态时电路中的混淆。由于这种编码相邻的两个码组之间只有一位不同,因而在用于模-数转换中,当模拟量发生微小变化而可能引起数字量发生变化时,格雷码仅改变一位,这样与其它码同时改变两位或多位的情况相比更为可靠,即可减少出错的可能性.这就允许代码电路能以较少的错误在较高的速度下工作。
  格雷码在现代科学上获得了广泛的应用,人们还发现智力玩具九连环的状态变化符合格雷码的编码规律,汉诺塔的解法也与格雷码有关。
  除了已知的特点,格雷码还有一些鲜为人知的性质。多数数字电子技术和计算机技术的文献认为格雷码是无权码,只有J.F.A.
Thompson认为可以从格雷码直接转换成十进制数[6]。如果将格雷码的“权”及格雷码的奇偶性等性质在数学上给予证明,将有助于格雷码研究与应用的发展,有助于自动化技术的发展,还可有助于计算机科学的发展。

/*   格雷码与二进制的转换程序
 * 本程序采用递推的方法进行推导,可以转换0~2147483647之间的数(1~31位)
 * 推导方式如下(以三位格雷码为例):
 * 序号 格雷码 格雷码实值 二进制码 二进制实值
 *  0  000   0   000   0
 *  1  001   1   001   1
 *  2  011   3   010   2
 *  3  010   2   011   3
 *  4  110   6   100   4
 *  5  111   7   101   5
 *  6  101   5   110   6
 *  7  100   4   111   7
 *     由上面的数据可看出.如果,按照序号01327645的方式遍历格雷码.其编
 * 码实值是按自然数顺序排列.反之,如果按此顺序遍历其二进制实值.则会发
 * 现遍历过的数据的个数减一即为二进制码所对应格雷码的实值.再观察序号
 * 顺序,我们会发现: 如果把二进制码分半,前半部分从前向后遍历,后半部分
 * 从后向前遍历.如果分半部分可再分,则再将其分半.并按照前半部分从前向
 * 后遍历(分解),后半部分从后向前遍历的方式遍历(分解).直到不可分.即可
 * 实现按序号所描述顺序遍历二进制码.如果,按此顺序遍历二进制码,我们可
 * 以很方便地在序列中找到所要的二进制码与其对应的格雷码.本思想可以很
 * 方便地用递归实现.这样就实现了二进制到格雷码的转换.同样,格雷码到二
 * 进制的转换,也可以用相同的方法推出.为了加快运算,我们跳过不必要的遍
 * 历将递归改为递推.这样就实现了格雷码与二进制之间的快速转换.
 * 此算法的时间复杂度约为O(n),n为要转换数据的BIT数.
 * *****************************************************************
 *  补充说明:
 *  其它的转换方法还有
 *    1、查表法(建立一个二进制与格雷码的对应表)
 *    2、公式法(根据卡诺图建立一个二进制到格雷码的每一位的公式)
 */
 
//#define test
#i nclude <stdio.h>
#ifdef test
 #i nclude <time.h>
#endif
/**
 * 二进制转换成格雷码
 * @param lStart lValue所在区间下界
 * @param lEnd lValue所在区间上界
 * @param lValue 要转换的二进制数的实值
 * @return 返回格雷码对应的二进制数的实值
 * @see g2b() g2b 格雷码转换二进制
 * @see BtoG() BtoG 二进制转换格雷码
 * @see GtoB() BtoG 格雷码转换二进制
 * @author 黄毅
 * @useage a=b2g(0,15,4); //取得4所对应格雷码的二进制值 结果a等于6
 * @memo lValue的值必须在区间[lStart,lEnd]里,否则无法求得所求结果.相应地,如果区间越小,求得结
 *       果所用的时间就越少.而且lStart,lEnd的值必须为2的N次方减1. 通常lStart为0.为了方便求得
 *       其值,建议使用BtoG()函数来进行操作.不过这样会使计算时间加长到原来的120%~180%.
 */
unsigned long b2g(unsigned long lStart,unsigned long lEnd,unsigned
long lValue)
{
 unsigned long Start=lStart,End=lEnd,Temp=0,Counter=0;
 bool Type=true;
 while(Start<End)
  {
   Temp=(End+Start-1)>>1;
   if (lValue<=Temp)
   {
    if(!Type)
     Counter+=((End-Start+1)>>1);
    End=Temp;
    Type=true;
   }
   else
   {
    if(Type)
     Counter+=((End-Start+1)>>1);
    Start=++Temp;
    Type=false;
   }
  }
 return Counter;
}
/**
 * 格雷码转换成二进制
 * @param lStart lValue对应二进制数所在区间下界
 * @param lEnd lValue对应二进制数所在区间上界
 * @param lValue 要转换的格雷码的实值
 * @return 返回二进制数对应的格雷码的实值
 * @see b2g() b2g 二进制转换格雷码
 * @see BtoG() BtoG 二进制转换格雷码
 * @see GtoB() BtoG 格雷码转换二进制
 * @author 黄毅
 * @useage a=b2g(0,15,6); //取得6所对应二进制值的格雷码 结果a等于4
 * @memo lValue对应二进制数的值必须在区间[lStart,lEnd]里,否则无法求得所求结果.相应地,如果区
 *       间越小,求得结果所用的时间就越少.而且lStart,lEnd的值必须为2的N次方减1. 通常lStart为0.
 *       为了方便求得其值,建议使用GtoB()函数来进行操作.但会使计算时间加长到原来的105%~140%.
 */
unsigned long g2b(unsigned long lStart,unsigned long lEnd,unsigned
long lValue)
{
 unsigned long Start=lStart,End=lEnd,Counter=0,Temp=0;
 bool Type=true;
 while(Start<End)
  {
   Temp=Counter+((End-Start+1)>>1);
   if(Type^(lValue<Temp))
   {
    if(Type) Counter=Temp;
    Start=(Start+End+1)>>1;
    Type=false;
   }
   else
   {
    if(!Type) Counter=Temp;
    End=(Start+End-1)>>1;
    Type=true;
   }
  }
 return Start;
}
//b2g外壳程序,用来算lStart,lEnd;
long BtoG(unsigned long lValue)
{
 register unsigned long lV=lValue,lMax=1;
 while (lV>0)
 {
  lV>>=1;
  lMax<<=1;
 }
 if (lMax==0) return -1;
 return b2g(0,--lMax,lValue);
}
//g2b外壳程序
long GtoB(unsigned long lValue)
{
 register unsigned long lV=lValue,lMax=1;
 while (lV>0)
 {
  lV>>=1;
  lMax<<=1;
 }
 if (lMax==0) return -1;
 return g2b(0,--lMax,lValue);
}

main()
{
 long input=0;
#ifdef test
//程序测试部分
 clock_t cStart,cEnd;
 unsigned long dTime;
 cStart=clock();
 for (input=0;input<9999999;input++)
  BtoG(32768);
 cEnd=clock();
 dTime=(cEnd-cStart);
 printf("BtoG: %ld / %ld\n",dTime,CLOCKS_PER_SEC);
//------------------------------------------------------
 cStart=clock();
 for (input=0;input<9999999;input++)
  b2g(0,65535,32768);
 cEnd=clock();
 
 dTime=(cEnd-cStart);
 printf("b2g: %ld / %ld\n",dTime,CLOCKS_PER_SEC);
//------------------------------------------------------
 cStart=clock();
 for (input=0;input<9999999;input++)
  GtoB(32768);
 cEnd=clock();
 dTime=(cEnd-cStart);
 printf("GtoB: %ld / %ld\n",dTime,CLOCKS_PER_SEC);
//------------------------------------------------------
 cStart=clock();
 for (input=0;input<9999999;input++)
  g2b(0,65535,32768);
 cEnd=clock();
 dTime=(cEnd-cStart);
 printf("g2b: %ld / %ld\n",dTime,CLOCKS_PER_SEC);
#else
//程序演试部分
 printf("Input(HEX):");
 scanf("%x",&input);
 while (input!=-1)
 {
  printf("------BtoG------\nBinary:%08Xh\nGray 
:%08Xh\n------GtoB------\nGray 
:%08Xh\nBinary:%08Xh\n----------------\n",input,BtoG(input),input,GtoB(input));
  printf("Input(HEX):");
  scanf("%x",&input);
 }
#endif


 
 
 
 
======================================================================================二进制格雷码与自然二进制码的互换(2)
三、二进制格雷码与自然二进制码互换的实现方法
1、自然二进制码转换成二进制格雷码
A)、软件实现法(参见示例工程中的 Binary to Gray)
根据自然二进制转换成格雷码的法则,可以得到以下的代码:
   static unsigned int DecimaltoGray(unsigned int x)
   {
     return x^(x>>1);
   }
   
   //以上代码实现了unsigned int型数据到格雷码的转换,最高可转换32位自然二进制码,超出32位将溢出。 
   static int DecimaltoGray( int x)
   {
     return x^(x>>1);
   }
   
   //以上代码实现了 int型数据到格雷码的转换,最高可转换31位自然二进制码,超出31位将溢出。   
  上述代码即可用于VC控制程序中,也可以用于单片机控制程序中。在单片机程序设计时,若采用汇编语言编程,可以按相同的原理设计程序;若采用C语言编程,则可以直接利用上述代码,但建议用unsigned int函数。
2、二进制格雷码转换成自然二进制码
A)、软件实现法(参见示例工程中的 Gray to Binary )
根据二进制格雷码转换成自然二进制码的法则,可以得到以下的三种代码方式:
    static unsigned int GraytoDecimal(unsigned int x)
    {
     unsigned int y = x;
     while(x>>=1)
      y ^= x;
     return y;
    }   
 
   static unsigned int GraytoDecimal(unsigned int x)
    {
     x^=x>>16;
     x^=x>>8;
     x^=x>>4;
     x^=X>>2;
     x^=x^1;
     return x;
    }   
 
   static unsigned int GraytoDecimal(unsigned int x)
    {
     int i;
     for(i=0;(1<<i)<sizeof(x)*8;i++)
     {
       x^=x>>(1<<i);
     }
     return x;
    }    
  //以上代码实现了unsigned int型数据到自然二进制码的转换,最高可转换32位格雷码,超出32位将溢出。将数据类型改为int型即可实现31位格雷码转换。
上述代码即可用于VC控制程序中,也可以用于单片机控制程序中。在单片机程序设计时,若采用汇编语言编程,可以按相同的原理设计程序;若采用C语言编程,则可以直接利用上述代码,但建议用unsigned int函数。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C语言打印二进制的代码
二进制格雷码与自然二进制码的互换
操作 变量 的某一位
计算无符号数中二进制1的个数 - C/C++ - 庸愚居
格雷编码
位操作相关技术
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服