打印

N位压缩BCD加法

[复制链接]
6074|29
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
雁舞白沙|  楼主 | 2007-3-13 09:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//extern unsigned char databuf[16];---此缓冲区0-3存放的是被加数,4-7存放的是加数,8-11存放的和。(低字节在前)
//扩展此缓冲区,便可以实现任意长度的压缩BCD加法
//*DataOneDptr==>被加数数组的指针
//*DataTwoDptr==>加数的数组指针

//作者:雁舞白沙
void DataAdd(unsigned char *DataOneDptr,unsigned char *DataTwoDptr,unsigned char DataLend)
{
    unsigned char data i,j,k,l;
    j=0;
    k=0;
    l=0;
    for(i=0;i<DataLend;i++)
    {       
        databuf=*DataOneDptr;
        databuf&=0x0f;
        databuf[i+4]=*DataTwoDptr;
        databuf[i+4]&=0x0f;
        for(j=0;j<2;j++)
        {
              k=databuf+databuf[i+4]+l;
              if(k>9)
              {
                  if(j==1)
                  {
                       k=k+6;
                       k=k<<4;
                       databuf[i+8]=databuf[i+8]+k;
                  }
                  else
                  {
                       databuf[i+8]=databuf[i+8]+k+6;
                       databuf[i+8]&=0x0f;
                  }
                  l=0x01;
              }
              else
              {
                  l=0x00;
                  if(j==1)
                  {
                       k=k<<4;
                       databuf[i+8]=databuf[i+8]+k;
                  }
                  else
                  {
                       k&=0x0f;
                       databuf[i+8]=k;
                  }
              }
              databuf=*DataOneDptr;
              databuf[i+4]=*DataTwoDptr;
              databuf=databuf>>4;
              databuf[i+4]=databuf[i+4]>>4;
        }
        DataOneDptr++;
        DataTwoDptr++;
    }   
}

程序昨天晚上完成,有不对的地方,欢迎大家更正!

相关帖子

沙发
xwj| | 2007-3-13 11:00 | 只看该作者

很不好!

1、结果不对
2、模块耦合性不好,藕断丝连
3、所谓的任意长度并不是真正的作为参数的任意长度
4、变量名不规范
5、代码效率低,RAM、ROM、速度都不好

你的程序看似用循环可以节约code,实际上却导致code用量更多:-)
占用资源:Program Size: data=30.0 xdata=0 code=270

我简单改了下,占用资源:
Program Size: data=28.0 xdata=0 code=138

//N位压缩BCD加法 

unsigned char idata databuf[16];    //---此缓冲区0-3存放的是被加 数,4-7存放的是加 数,8-11存放的和。扩展此缓冲区,便可以实现任意长度的压缩BCD加法

/***************************************************/
//xwj修改的程序:
//入口:
//*dataOneDptr==>被加数数组的指针
//*dataTwoDptr==>加数的数组指针
// dataLend   ==>数据字节数
//出口:
//*dataTwoDptr==>结果的数组指针,也可简单修改保存到*dataOneDptr地址
void dataAdd(unsigned char idata *dataOneDptr,unsigned char idata *dataTwoDptr,unsigned char dataLend)
{
    unsigned char low,high,buf1,buf2,over;
    over=0;
    while(dataLend--)
    {
        buf1=*dataOneDptr;
        buf2=*dataTwoDptr;
        low=(buf1&0x0f) + (buf2&0x0f) +over;
        if(low>0x09)
        {
            low=low-10; 
            over=1;
        }
        else
            over=0;
        high=(buf1>>4) + (buf2>>4) + over;
        if(high>0x09) 
        {
            high=high-10; 
            over=1;
        }
        else
            over=0;
        
        *dataTwoDptr= low + (high<<4);
        dataOneDptr++;
        dataTwoDptr++;
    }   
}
 
/***************************************************/
void main(void)        //测试程序
{
    unsigned char i;
    databuf[7]=0x12;
    databuf[6]=0x34;
    databuf[5]=0x56;
    databuf[4]=0x78;
    while(1)
    {
        for(i=0;i<4;i++)
        {
            databuf=0x11;
        }
        dataAdd(databuf,&databuf[4],4);
    }
}
//本程序由xwj设计的UltraEdit脚本加亮显示,如需要脚本访问我的Blog 或发送邮件至:xwjfile@21cn.com

//呵呵,真是50步笑百步了,我的也有明显BUG,还是改一下的好,免得贻笑大方:-)

使用特权

评论回复
板凳
xwj| | 2007-3-13 11:09 | 只看该作者

看似没什么技巧的代码,但ROM烧了一半,速度快了好几倍

斟误:
对应入口说明
//*dataOneDptr==>被加数数组的指针
//*dataTwoDptr==>加数的数组指针
这两句:
        buf1=*dataOneDptr;
        buf2=*(dataOneDptr+dataLend);
应该改成:
        buf1=*dataOneDptr;
        buf2=*dataTwoDptr;

使用特权

评论回复
地板
雁舞白沙|  楼主 | 2007-3-13 11:14 | 只看该作者

谢谢!

使用特权

评论回复
5
xwj| | 2007-3-13 11:14 | 只看该作者

呵呵,仔细想了下我的程序还有个隐秘的BUG,先不说,看看谁能

:-)

使用特权

评论回复
6
农民讲习所| | 2007-3-13 11:20 | 只看该作者

用算法处理好些:

void DataAdd(unsigned char *DataOneDptr,unsigned char *DataTwoDptr,unsigned char DataLend)
{
    unsigned char bLogic = 0;   
    unsigned char bCarry = 0;
    unsigned char i;
    unsigned char j;

    while( DataLedn-- ){
L_Loop:
      j = *DataOneDptr;

      if( !bLogic ){
          i = ( *DataTwoDptr & 0xf )+ ( j & 0xf ) + bCarry;
          if( i>9 ){
             i -= 9;
             bCarry = 1;
          }
          *DataOneDptr = ( j&0xf0 ) | i;

          bLogic = 1;
      }
      else {
          i = ( *DataTwoDptr++ >>4 )+ ( j >>4 ) + bCarry;
          if( i>9 ){
             i -= 9;
             bCarry = 1;
          }
          i <<= 4;
          *DataOneDptr++ = ( j&0x0f ) | i;
          
          bLogic = 0;
      }
    }

    //最后进位处理
    if( bCarry ){
       DataLedn = 1;
       goto L_Loop;
    }
}

不要这样:unsigned char data i,j,k,l;
定义局部变量不要使用data、idata、xdata之类。

使用特权

评论回复
7
xwj| | 2007-3-13 12:11 | 只看该作者

农民讲习所 得程序有问题, goto

使用特权

评论回复
8
hotpower| | 2007-3-13 12:45 | 只看该作者

又开战了???

我记得BCD码调整没这么复杂吧~~~晚上有空也参战参战~~~

使用特权

评论回复
9
xwj| | 2007-3-13 12:52 | 只看该作者

呵呵,等着晚上看你的好戏:-)

使用特权

评论回复
10
雁舞白沙|  楼主 | 2007-3-13 13:06 | 只看该作者

XWJ你的程序很好!

但是考虑到做电磁兼容试验的时候,有可能导致原数组错误,故此特意复制到databuf;

避免在转换的时候不会发生以外时间!

使用特权

评论回复
11
hotpower| | 2007-3-13 16:01 | 只看该作者

这能叫BCD???倒塌了~~~看看菜农的图片

这是按大端做的~~~

使用特权

评论回复
12
hotpower| | 2007-3-13 16:04 | 只看该作者

再搞个组图~~~






使用特权

评论回复
13
xwj| | 2007-3-13 16:38 | 只看该作者

第24行根本不需要那样判断

使用特权

评论回复
14
雁舞白沙|  楼主 | 2007-3-13 17:02 | 只看该作者

都是高人啊!

惭愧啊,偶的代码最大了!

以后不敢随意发程序了!

使用特权

评论回复
15
xwj| | 2007-3-13 17:06 | 只看该作者

HotPower,俺测试了,你的那个代码大了一点,速度慢了一点点

Keil 和LZ的程序都是按小端来的,常用的ARM、电脑的CPU也都是按小端存储的,
你凭啥要把它改成大端啊???

不合要求,拉出去打PP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

使用特权

评论回复
16
xwj| | 2007-3-13 17:18 | 只看该作者

而且,偶滴程序只要低4位,效率也不低,你凭啥说减10的是混

实在是胡说八道,再拉出去打PP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

使用特权

评论回复
17
hotpower| | 2007-3-13 17:54 | 只看该作者

我倒塌了~~~51就是按大端存储的,为何打PP???

unsigned char databuf[24];//64位BCD加法缓冲区
unsigned char DataAdd(unsigned char *,unsigned char *,unsigned char);

void main()
{
unsigned char val;
//8位BCD加法(12 + 78 = 90)
  (unsigned char)databuf[1] = 0x12;
  (unsigned char)databuf[2] = 0x78;
  val = DataAdd(&databuf[1], &databuf[2], 1);//结果在val和databuf[1]中
//16位BCD加法(1234 + 5678 = 6912)
  (unsigned int)databuf[2] = 0x1234;
  (unsigned int)databuf[4] = 0x5678;
  val = DataAdd(&databuf[2], &databuf[4], 2);//结果在val和databuf[0]~databuf[1]中
//24位BCD加法(123456 + 456789 = 580245)
  (unsigned char)databuf[3] = 0x12;
  (unsigned int) databuf[4] = 0x3456;
  (unsigned char)databuf[6] = 0x45;
  (unsigned int) databuf[7] = 0x6789;
  val = DataAdd(&databuf[3], &databuf[6], 3);//结果在val和databuf[0]~databuf[2]中
//32位BCD加法(12345678 + 88888888 = 1 01234566)
  (unsigned long)databuf[4] = 0x12345678L;
  (unsigned long)databuf[8] = 0x88888888L;
  val = DataAdd(&databuf[4], &databuf[8], 4);//结果在val和databuf[0]~databuf[3]中
//64位BCD加法(1111111122222222 + 8888888899999999 = 1 0000000022222221)
  (unsigned long)databuf[8]  = 0x11111111L;
  (unsigned long)databuf[12] = 0x22222222L;

  (unsigned long)databuf[16] = 0x88888888L;
  (unsigned long)databuf[20] = 0x99999999L;
  val = DataAdd(&databuf[8], &databuf[16], 8);//结果在val和databuf[0]~databuf[7]中
  while(1)
  {
  }
}

unsigned char DataAdd(unsigned char *DataOneDptr,unsigned char *DataTwoDptr,unsigned char DataLend)
{
unsigned char One, Two, Tmp;//中间变量
unsigned int Sum = 0;//考虑CY位故取整型
  while(DataLend) {//不能DataLend--或--DataLend
    DataLend --;//调整到正确的数组位置
    One = DataOneDptr[DataLend];//取出正确的被加数
    Two = DataTwoDptr[DataLend];//取出正确的加数
    Sum = One + Two + Sum;//二进制求和(注意上次低位向高位的进位)
    Tmp = (One & 0xf0) + (Two & 0xf0);//为半进位做准备
    if ((Tmp != (Sum & 0xf0)) || ((Sum & 0x0f) > 9)) {//BCD码低4位调整
      Sum += 6;//凡加减10或9的都是"混球"~~~
    }
    if (Sum >= 0xa0) {//BCD码高4位调整
      Sum += 0x60;//注意"混球"~~~
    }
    databuf[DataLend] = Sum;//只存入低8位
    Sum >>= 8;//保留高8位做为下次低位向高位的进位
  }
  return Sum;//返回溢出标志(最高1位)
}

使用特权

评论回复
18
lenglx| | 2007-3-13 18:15 | 只看该作者

呵呵

hotpower的程序正解.
2楼的那段程序好像没有检查1位BCD相加后产生(半)进位的情况吧.
比如 58+69 这样的式子,用2楼的算**出错的.

不过个人以为:象这种BCD的计算,如果用纯粹的C语言实现,玩的成分居多.
实际工程中应用不大.

51中提供10进制加法调整的指令,X86中甚至还有10进制减法调整的指令.岂不是浪费.
用1条指令就能完成的事情,何苦非要用几十上百条指令来做这个事情.


不过ARM中好像没有用于BCD调整的指令哈.:)

使用特权

评论回复
19
hotpower| | 2007-3-13 18:31 | 只看该作者

哈哈~~~ARM的BCD有何难???不就是"男左女右"搞小端嘛

哈哈~~~帖个ARM程序,别让人说我在抄书~~~
算法嘛,不就是动动脑筋,吹吹气这么简单吗~~~

使用特权

评论回复
20
lenglx| | 2007-3-13 18:37 | 只看该作者

废话

用C实现,在哪个芯片上不是一样.

无非就是如果产生半进位(进位)或者结果大于9(0x90),就加上6(0x60),这样一个概念而已.

我是说,如果用汇编,51中一条DAA指令解决问题.ARM中如何?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

213

主题

789

帖子

243

粉丝