搜索
bottom↓
回复: 28

悬赏!怎么最快的求数字的各位数字

[复制链接]

出500入0汤圆

发表于 2013-2-6 13:33:29 | 显示全部楼层 |阅读模式
常用的:

        temp[0]=number%100000000/10000000+48;
        temp[1]=number%10000000/1000000+48;
        temp[2]=number%1000000/100000+48;
        temp[3]=number%100000/10000+48;
        temp[4]=number%10000/1000+48;
        temp[5]=number%1000/100+48;
        temp[6]=number%100/10+48;
        temp[7]=number%10+48;

就是计算量有点大,很耗时,求效率高的算法,谢谢!

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出20入186汤圆

发表于 2013-2-6 13:35:30 | 显示全部楼层

volatile uint8_t tostr_reg[15];        //数字转字符

uint8_t * numtostr(uint32_t num,uint32_t len,uint32_t min){        //数字转换为字符,存储在 tostr_reg  数字,需要长度(含 小数点),小数位数
        uint32_t i;
        for(i=len;i>0;i--){        //124.3  00100.0
                if(min&&(min==len-i))
                        tostr_reg[i-1]='.';
                else{
                        tostr_reg[i-1]=(num % 10) + 0x30;
                        num/=10;
                }
        }
        tostr_reg[len]=0;
        return (uint8_t *)&tostr_reg[0];
}

我一个项目里用的,

出20入186汤圆

发表于 2013-2-6 13:37:05 | 显示全部楼层
比如 数字 123需要转换成字符 “12.3"
则调用  numtostr(123,4,1)
返回的是转换好的字符指针

出0入0汤圆

发表于 2013-2-6 13:44:09 | 显示全部楼层
不知道楼主要处理的数据是否为浮点数?

出0入17汤圆

发表于 2013-2-6 13:45:45 | 显示全部楼层
楼主是几位单片机?

出0入0汤圆

发表于 2013-2-6 13:49:05 | 显示全部楼层
如果只要时间最快,就用查表,只是要牺牲很大很大的空间。

出500入0汤圆

 楼主| 发表于 2013-2-6 14:17:10 | 显示全部楼层
用的AVR,处理的长整形,晶振1M,资源比较紧张啊

出500入0汤圆

 楼主| 发表于 2013-2-6 14:18:21 | 显示全部楼层
lugang_2920213 发表于 2013-2-6 13:44
不知道楼主要处理的数据是否为浮点数?

长整型,需要知道低八位

出500入0汤圆

 楼主| 发表于 2013-2-6 14:18:51 | 显示全部楼层
yuyu87 发表于 2013-2-6 13:37
比如 数字 123需要转换成字符 “12.3"
则调用  numtostr(123,4,1)
返回的是转换好的字符指针 ...

程序看懂了,看有没有更好的,谢谢!

出500入0汤圆

 楼主| 发表于 2013-2-6 14:19:17 | 显示全部楼层
hhxb 发表于 2013-2-6 13:45
楼主是几位单片机?

AVR,8位的

出500入0汤圆

 楼主| 发表于 2013-2-6 14:19:51 | 显示全部楼层
.titrwh 发表于 2013-2-6 13:49
如果只要时间最快,就用查表,只是要牺牲很大很大的空间。

这个查表的话需要的空间太大了

出20入186汤圆

发表于 2013-2-6 14:27:46 | 显示全部楼层
JamesErik 发表于 2013-2-6 14:18
程序看懂了,看有没有更好的,谢谢!

我感觉还可以,自己写的,你到网上搜下吧,类似的代码蛮多的

出20入186汤圆

发表于 2013-2-6 14:28:55 | 显示全部楼层
JamesErik 发表于 2013-2-6 14:17
用的AVR,处理的长整形,晶振1M,资源比较紧张啊

1M晶振?也太小了点吧?那你这样计算一下20mS都不止

出500入0汤圆

 楼主| 发表于 2013-2-6 14:32:10 | 显示全部楼层
yuyu87 发表于 2013-2-6 14:28
1M晶振?也太小了点吧?那你这样计算一下20mS都不止

被光耦整了,只好降低晶振了

出0入8汤圆

发表于 2013-2-6 14:37:16 | 显示全部楼层
再快也得要做8次除法,还是余数和商同时得到的那种
你的数据中间需要做运算吗?如果不需要可以把数据直接存成BCD的形式
如果只做加减,用BCD也还能解决

出500入0汤圆

 楼主| 发表于 2013-2-6 14:39:02 | 显示全部楼层
canspider 发表于 2013-2-6 14:37
再快也得要做8次除法,还是余数和商同时得到的那种
你的数据中间需要做运算吗?如果不需要可以把数据直接存 ...

一般是求出来给串口或者1602之类的

出0入93汤圆

发表于 2013-2-6 14:43:16 | 显示全部楼层
AVR,8位的,1M晶振,有整数硬件乘法及定点小数硬件乘法,没有硬件除法。因此,凡是出现了/、%的效率都不可能高,代码也不可能少。必须转换成移位、乘法和减法,极有可能配合查表。

你到底是要效率(时间)还是ROM占用(空间),还是两者兼顾?要效率ROM占用就大,要ROM占用小效率必然比较低,两者兼顾则两者都存在短处,你究竟想如何取舍?

出0入93汤圆

发表于 2013-2-6 14:51:48 | 显示全部楼层
JamesErik 发表于 2013-2-6 14:18
长整型,需要知道低八位

是输入的范围是0~99999999还是在整个long范围内的数值只截取低八位(比如允许100000002,但是只显示2)?两者差异特别大

出500入0汤圆

 楼主| 发表于 2013-2-6 14:59:59 | 显示全部楼层
takashiki 发表于 2013-2-6 14:51
是输入的范围是0~99999999还是在整个long范围内的数值只截取低八位(比如允许100000002,但是只显示2)? ...

数值只在xxxxxxxx(8)内

出0入93汤圆

发表于 2013-2-6 15:40:28 | 显示全部楼层
本帖最后由 takashiki 于 2013-2-6 15:43 编辑

侧重效率的算法

刚才自己稍微算了一下,32位的乘法以及移位效率也不高,还不如直接辗转相减呢。总的时间占用没有详细计算,只提供方案如下,占用Flash很大的。假设输入的为long Input,输出为char temp[9]。temp[8]总是为0,以便于字符串的计算。
  1. char temp[9];

  2. void LongToStr(long Input){                //针对你这个具体项目进行计算
  3.         char c;                                    //目的是尽量使编译器使用寄存器而不是变量,因为AVR的内存访问效率较低。
  4.         unsigned short wordInput;
  5.         unsigned char bytInput;
  6.        
  7.         c = '0';                                   //计算最高位
  8.         if(Input >= 8000000) c += 8, Input -= 8000000;
  9.         if(Input >= 4000000) c += 4, Input -= 4000000;
  10.         if(Input >= 2000000) c += 2, Input -= 2000000;
  11.         if(Input >= 1000000) c += 1, Input -= 1000000;
  12.         temp[0] = c;
  13.        
  14.         c = '0';                                   //计算第二位
  15.         if(Input >= 800000) c += 8, Input -= 800000;
  16.         if(Input >= 400000) c += 4, Input -= 400000;
  17.         if(Input >= 200000) c += 2, Input -= 200000;
  18.         if(Input >= 100000) c += 1, Input -= 100000;
  19.         temp[1] = c;
  20.        
  21.         c = '0';
  22.         if(Input >= 80000) c += 8, Input -= 80000;
  23.         if(Input >= 40000) c += 4, Input -= 40000;
  24.        
  25.         //到这里为止,Input一定小于40000,因此可以采用short类型了!
  26.         wordInput = (unsigned short)Input;
  27.         if(wordInput >= 20000) c += 2, wordInput -= 20000;
  28.         if(wordInput >= 10000) c += 1, wordInput -= 10000;
  29.         temp[2] = c;       
  30.        
  31.         c = '0';
  32.         if(wordInput >= 8000) c += 8, wordInput -= 8000;
  33.         if(wordInput >= 4000) c += 4, wordInput -= 4000;
  34.         if(wordInput >= 2000) c += 2, wordInput -= 2000;
  35.         if(wordInput >= 1000) c += 1, wordInput -= 1000;
  36.         temp[3] = c;
  37.        
  38.         temp[4] = (wordInput * 205u) >> 11;
  39.         bytInput = wordInput - temp[4] * 10;
  40.        
  41.         temp[5] = (unsigned char)((bytInput * 205u)>>8) >> 3;
  42.         bytInput = wordInput - temp[5] * 10;
  43.        
  44.         temp[6] = (unsigned char)((bytInput * 205u)>>8) >> 3;
  45.         temp[7] = wordInput - temp[6] * 10;       
  46.         temp[8] = 0;
  47. }
复制代码
后面的<1000的计算参见我的一个帖子:AVR中除10的优化算法

出0入17汤圆

发表于 2013-2-6 16:03:44 | 显示全部楼层
楼上强悍呀

出0入0汤圆

发表于 2013-2-6 18:27:01 | 显示全部楼层
/******long变量转换为字符串*******/
static char *ltoa(unsigned long value)
{
unsigned char *ptr=FRE_BUF2;
unsigned long i=1000000000,d;
do
{
  d=value/i;//取最高位
  *ptr++ = (char)(d + 0x30);//存放到FRE_BUF2[0......9]//*ptr先赋值再自加
  value -= (d * i);
}
  while(i/=10);
return FRE_BUF2;
}
代码不长,除法还在

出500入0汤圆

 楼主| 发表于 2013-2-6 19:08:48 | 显示全部楼层
takashiki 发表于 2013-2-6 15:40
侧重效率的算法

刚才自己稍微算了一下,32位的乘法以及移位效率也不高,还不如直接辗转相减呢。总的时间占 ...

这个牛逼了,初略看不懂,没有除法了,效率应该好很多,看另外帖子的讨论,这个做了近似处理吗?

出0入93汤圆

发表于 2013-2-6 22:06:50 | 显示全部楼层
JamesErik 发表于 2013-2-6 19:08
这个牛逼了,初略看不懂,没有除法了,效率应该好很多,看另外帖子的讨论,这个做了近似处理吗? ...


是的,做了近似处理。所以只有最后面的三位采用了乘法+移位方式,前面的没有,因为会有误差。<1000的使用乘法+移位方式是没有误差的,我当时每一个数字都对比过的。

其实原理很简单,对于每一位来说,采用8421码分别对比,其实就相当于我们小学时学过的除法的试商,只是全部展开了。
减到40000以下时,使用2个字节表示已经足够了,为了效率的考虑,于是单独拿出来特殊处理。

PS:
进一步优化效率,>8[n个0]后必定不可能大于1[n个0]了,因此可以再减少2次判断,优化后的片段如下:
  1. c = '0';                                   //计算最高位
  2. if(Input >= 8000000) c += 8, Input -= 8000000;
  3. else {
  4.        if(Input >= 4000000) c += 4, Input -= 4000000;
  5.        if(Input >= 2000000) c += 2, Input -= 2000000;
  6. }
  7. if(Input >= 1000000) c += 1, Input -= 1000000;
  8. temp[0] = c;
复制代码
其他的依此类推。

出0入0汤圆

发表于 2013-2-6 22:54:38 | 显示全部楼层
标记一下,高速ltoa算法。

出70入0汤圆

发表于 2013-2-7 14:57:42 | 显示全部楼层
你思路是否有问题,钻牛角尖可不好,仅仅是一个显示在那里瞎折腾,你的项目的数据变化率有多快?是否真的需要那么快才可以满足要求的,1602的显示速率那么低,变化那么快根本看不清有何意义,你计算那么快干嘛。。。脑筋转下弯吧
    实在不行可以用16进制显示,这个超快,乘除法都没用到。

出500入0汤圆

 楼主| 发表于 2013-2-7 15:15:08 | 显示全部楼层
takashiki 发表于 2013-2-6 22:06
是的,做了近似处理。所以只有最后面的三位采用了乘法+移位方式,前面的没有,因为会有误差。8[n个0]后必 ...

我不知道怎么算周期,我自己弄了一个这个
  1. unsigned char u2s_temp[9];
  2. unsigned char* ulong_to_str(long int num)
  3. {
  4.     //usart_transmit_string("A");
  5.         u2s_temp[0]='\0';//结束标记
  6.                  if(num>89999999) {u2s_temp[8]=9+'0';num=num-90000000;}
  7.     else if(num>79999999) {u2s_temp[8]=8+'0';num=num-80000000;}
  8.     else if(num>69999999) {u2s_temp[8]=7+'0';num=num-70000000;}
  9.     else if(num>59999999) {u2s_temp[8]=6+'0';num=num-60000000;}
  10.     else if(num>49999999) {u2s_temp[8]=5+'0';num=num-50000000;}
  11.     else if(num>39999999) {u2s_temp[8]=4+'0';num=num-40000000;}
  12.     else if(num>29999999) {u2s_temp[8]=3+'0';num=num-30000000;}
  13.     else if(num>19999999) {u2s_temp[8]=2+'0';num=num-20000000;}
  14.     else if(num> 9999999) {u2s_temp[8]=1+'0';num=num-10000000;}
  15.     else u2s_temp[8]=0+'0';
  16.    
  17.              if(num>8999999) {u2s_temp[7]=9+'0';num=num-9000000;}
  18.     else if(num>7999999) {u2s_temp[7]=8+'0';num=num-8000000;}
  19.     else if(num>6999999) {u2s_temp[7]=7+'0';num=num-7000000;}
  20.     else if(num>5999999) {u2s_temp[7]=6+'0';num=num-6000000;}
  21.     else if(num>4999999) {u2s_temp[7]=5+'0';num=num-5000000;}
  22.     else if(num>3999999) {u2s_temp[7]=4+'0';num=num-4000000;}
  23.     else if(num>2999999) {u2s_temp[7]=3+'0';num=num-3000000;}
  24.     else if(num>1999999) {u2s_temp[7]=2+'0';num=num-2000000;}
  25.     else if(num> 999999) {u2s_temp[7]=1+'0';num=num-1000000;}
  26.     else u2s_temp[7]=0+'0';
  27.    
  28.              if(num>899999) {u2s_temp[6]=9+'0';num=num-900000;}
  29.     else if(num>799999) {u2s_temp[6]=8+'0';num=num-800000;}
  30.     else if(num>699999) {u2s_temp[6]=7+'0';num=num-700000;}
  31.     else if(num>599999) {u2s_temp[6]=6+'0';num=num-600000;}
  32.     else if(num>499999) {u2s_temp[6]=5+'0';num=num-500000;}
  33.     else if(num>399999) {u2s_temp[6]=4+'0';num=num-400000;}
  34.     else if(num>299999) {u2s_temp[6]=3+'0';num=num-300000;}
  35.     else if(num>199999) {u2s_temp[6]=2+'0';num=num-200000;}
  36.     else if(num> 99999) {u2s_temp[6]=1+'0';num=num-100000;}
  37.     else u2s_temp[6]=0+'0';
  38.    
  39.              if(num>89999) {u2s_temp[5]=9+'0';num=num-90000;}
  40.     else if(num>79999) {u2s_temp[5]=8+'0';num=num-80000;}
  41.     else if(num>69999) {u2s_temp[5]=7+'0';num=num-70000;}
  42.     else if(num>59999) {u2s_temp[5]=6+'0';num=num-60000;}
  43.     else if(num>49999) {u2s_temp[5]=5+'0';num=num-50000;}
  44.     else if(num>39999) {u2s_temp[5]=4+'0';num=num-40000;}
  45.     else if(num>29999) {u2s_temp[5]=3+'0';num=num-30000;}
  46.     else if(num>19999) {u2s_temp[5]=2+'0';num=num-20000;}
  47.     else if(num> 9999) {u2s_temp[5]=1+'0';num=num-10000;}
  48.     else u2s_temp[5]=0+'0';
  49.    
  50.              if(num>8999) {u2s_temp[4]=9+'0';num=num-9000;}
  51.     else if(num>7999) {u2s_temp[4]=8+'0';num=num-8000;}
  52.     else if(num>6999) {u2s_temp[4]=7+'0';num=num-7000;}
  53.     else if(num>5999) {u2s_temp[4]=6+'0';num=num-6000;}
  54.     else if(num>4999) {u2s_temp[4]=5+'0';num=num-5000;}
  55.     else if(num>3999) {u2s_temp[4]=4+'0';num=num-4000;}
  56.     else if(num>2999) {u2s_temp[4]=3+'0';num=num-3000;}
  57.     else if(num>1999) {u2s_temp[4]=2+'0';num=num-2000;}
  58.     else if(num> 999) {u2s_temp[4]=1+'0';num=num-1000;}
  59.     else u2s_temp[4]=0+'0';
  60.    
  61.              if(num>899) {u2s_temp[3]=9+'0';num=num-900;}
  62.     else if(num>799) {u2s_temp[3]=8+'0';num=num-800;}
  63.     else if(num>699) {u2s_temp[3]=7+'0';num=num-700;}
  64.     else if(num>599) {u2s_temp[3]=6+'0';num=num-600;}
  65.     else if(num>499) {u2s_temp[3]=5+'0';num=num-500;}
  66.     else if(num>399) {u2s_temp[3]=4+'0';num=num-400;}
  67.     else if(num>299) {u2s_temp[3]=3+'0';num=num-300;}
  68.     else if(num>199) {u2s_temp[3]=2+'0';num=num-200;}
  69.     else if(num> 99) {u2s_temp[3]=1+'0';num=num-100;}
  70.     else u2s_temp[3]=0+'0';
  71.    
  72.              if(num>89) {u2s_temp[2]=9+'0';num=num-90;}
  73.     else if(num>79) {u2s_temp[2]=8+'0';num=num-80;}
  74.     else if(num>69) {u2s_temp[2]=7+'0';num=num-70;}
  75.     else if(num>59) {u2s_temp[2]=6+'0';num=num-60;}
  76.     else if(num>49) {u2s_temp[2]=5+'0';num=num-50;}
  77.     else if(num>39) {u2s_temp[2]=4+'0';num=num-40;}
  78.     else if(num>29) {u2s_temp[2]=3+'0';num=num-30;}
  79.     else if(num>19) {u2s_temp[2]=2+'0';num=num-20;}
  80.     else if(num> 9) {u2s_temp[2]=1+'0';num=num-10;}
  81.     else u2s_temp[2]=0+'0';
  82.    
  83.     u2s_temp[1]=num+'0';
  84.    
  85.     return u2s_temp;
  86. }
复制代码
原理应该没有问题,还没有实验

没有乘除法了,就是代码量很大

出0入0汤圆

发表于 2013-2-7 22:36:55 来自手机 | 显示全部楼层
这个好久以前都讨论过:怎么还在讨论?要学会搜索 !

出0入0汤圆

发表于 2013-2-8 01:54:40 来自手机 | 显示全部楼层
sprintf王道...
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 08:19

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表