悬赏!怎么最快的求数字的各位数字
常用的:temp=number%100000000/10000000+48;
temp=number%10000000/1000000+48;
temp=number%1000000/100000+48;
temp=number%100000/10000+48;
temp=number%10000/1000+48;
temp=number%1000/100+48;
temp=number%100/10+48;
temp=number%10+48;
就是计算量有点大,很耗时,求效率高的算法,谢谢!
volatile uint8_t tostr_reg; //数字转字符
uint8_t * numtostr(uint32_t num,uint32_t len,uint32_t min){ //数字转换为字符,存储在 tostr_reg数字,需要长度(含 小数点),小数位数
uint32_t i;
for(i=len;i>0;i--){ //124.300100.0
if(min&&(min==len-i))
tostr_reg='.';
else{
tostr_reg=(num % 10) + 0x30;
num/=10;
}
}
tostr_reg=0;
return (uint8_t *)&tostr_reg;
}
我一个项目里用的, 比如 数字 123需要转换成字符 “12.3"
则调用numtostr(123,4,1)
返回的是转换好的字符指针 不知道楼主要处理的数据是否为浮点数? 楼主是几位单片机? 如果只要时间最快,就用查表,只是要牺牲很大很大的空间。 用的AVR,处理的长整形,晶振1M,资源比较紧张啊 lugang_2920213 发表于 2013-2-6 13:44 static/image/common/back.gif
不知道楼主要处理的数据是否为浮点数?
长整型,需要知道低八位 yuyu87 发表于 2013-2-6 13:37 static/image/common/back.gif
比如 数字 123需要转换成字符 “12.3"
则调用numtostr(123,4,1)
返回的是转换好的字符指针 ...
程序看懂了,看有没有更好的,谢谢! hhxb 发表于 2013-2-6 13:45 static/image/common/back.gif
楼主是几位单片机?
AVR,8位的 .titrwh 发表于 2013-2-6 13:49 static/image/common/back.gif
如果只要时间最快,就用查表,只是要牺牲很大很大的空间。
这个查表的话需要的空间太大了 JamesErik 发表于 2013-2-6 14:18 static/image/common/back.gif
程序看懂了,看有没有更好的,谢谢!
我感觉还可以,自己写的,你到网上搜下吧,类似的代码蛮多的 JamesErik 发表于 2013-2-6 14:17 static/image/common/back.gif
用的AVR,处理的长整形,晶振1M,资源比较紧张啊
1M晶振?也太小了点吧?那你这样计算一下20mS都不止 yuyu87 发表于 2013-2-6 14:28 static/image/common/back.gif
1M晶振?也太小了点吧?那你这样计算一下20mS都不止
被光耦整了,只好降低晶振了 再快也得要做8次除法,还是余数和商同时得到的那种
你的数据中间需要做运算吗?如果不需要可以把数据直接存成BCD的形式
如果只做加减,用BCD也还能解决 canspider 发表于 2013-2-6 14:37 static/image/common/back.gif
再快也得要做8次除法,还是余数和商同时得到的那种
你的数据中间需要做运算吗?如果不需要可以把数据直接存 ...
一般是求出来给串口或者1602之类的 AVR,8位的,1M晶振,有整数硬件乘法及定点小数硬件乘法,没有硬件除法。因此,凡是出现了/、%的效率都不可能高,代码也不可能少。必须转换成移位、乘法和减法,极有可能配合查表。
你到底是要效率(时间)还是ROM占用(空间),还是两者兼顾?要效率ROM占用就大,要ROM占用小效率必然比较低,两者兼顾则两者都存在短处,你究竟想如何取舍? JamesErik 发表于 2013-2-6 14:18 static/image/common/back.gif
长整型,需要知道低八位
是输入的范围是0~99999999还是在整个long范围内的数值只截取低八位(比如允许100000002,但是只显示2)?两者差异特别大 takashiki 发表于 2013-2-6 14:51 static/image/common/back.gif
是输入的范围是0~99999999还是在整个long范围内的数值只截取低八位(比如允许100000002,但是只显示2)? ...
数值只在xxxxxxxx(8)内{:biggrin:} 本帖最后由 takashiki 于 2013-2-6 15:43 编辑
侧重效率的算法
刚才自己稍微算了一下,32位的乘法以及移位效率也不高,还不如直接辗转相减呢。总的时间占用没有详细计算,只提供方案如下,占用Flash很大的。假设输入的为long Input,输出为char temp。temp总是为0,以便于字符串的计算。char temp;
void LongToStr(long Input){ //针对你这个具体项目进行计算
char c; //目的是尽量使编译器使用寄存器而不是变量,因为AVR的内存访问效率较低。
unsigned short wordInput;
unsigned char bytInput;
c = '0'; //计算最高位
if(Input >= 8000000) c += 8, Input -= 8000000;
if(Input >= 4000000) c += 4, Input -= 4000000;
if(Input >= 2000000) c += 2, Input -= 2000000;
if(Input >= 1000000) c += 1, Input -= 1000000;
temp = c;
c = '0'; //计算第二位
if(Input >= 800000) c += 8, Input -= 800000;
if(Input >= 400000) c += 4, Input -= 400000;
if(Input >= 200000) c += 2, Input -= 200000;
if(Input >= 100000) c += 1, Input -= 100000;
temp = c;
c = '0';
if(Input >= 80000) c += 8, Input -= 80000;
if(Input >= 40000) c += 4, Input -= 40000;
//到这里为止,Input一定小于40000,因此可以采用short类型了!
wordInput = (unsigned short)Input;
if(wordInput >= 20000) c += 2, wordInput -= 20000;
if(wordInput >= 10000) c += 1, wordInput -= 10000;
temp = c;
c = '0';
if(wordInput >= 8000) c += 8, wordInput -= 8000;
if(wordInput >= 4000) c += 4, wordInput -= 4000;
if(wordInput >= 2000) c += 2, wordInput -= 2000;
if(wordInput >= 1000) c += 1, wordInput -= 1000;
temp = c;
temp = (wordInput * 205u) >> 11;
bytInput = wordInput - temp * 10;
temp = (unsigned char)((bytInput * 205u)>>8) >> 3;
bytInput = wordInput - temp * 10;
temp = (unsigned char)((bytInput * 205u)>>8) >> 3;
temp = wordInput - temp * 10;
temp = 0;
}后面的<1000的计算参见我的一个帖子:AVR中除10的优化算法 楼上强悍呀 /******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//*ptr先赋值再自加
value -= (d * i);
}
while(i/=10);
return FRE_BUF2;
}
代码不长,除法还在 takashiki 发表于 2013-2-6 15:40 static/image/common/back.gif
侧重效率的算法
刚才自己稍微算了一下,32位的乘法以及移位效率也不高,还不如直接辗转相减呢。总的时间占 ...
这个牛逼了,初略看不懂,没有除法了,效率应该好很多,看另外帖子的讨论,这个做了近似处理吗? JamesErik 发表于 2013-2-6 19:08 static/image/common/back.gif
这个牛逼了,初略看不懂,没有除法了,效率应该好很多,看另外帖子的讨论,这个做了近似处理吗? ...
是的,做了近似处理。所以只有最后面的三位采用了乘法+移位方式,前面的没有,因为会有误差。<1000的使用乘法+移位方式是没有误差的,我当时每一个数字都对比过的。
其实原理很简单,对于每一位来说,采用8421码分别对比,其实就相当于我们小学时学过的除法的试商,只是全部展开了。
减到40000以下时,使用2个字节表示已经足够了,为了效率的考虑,于是单独拿出来特殊处理。
PS:
进一步优化效率,>8后必定不可能大于1了,因此可以再减少2次判断,优化后的片段如下:c = '0'; //计算最高位
if(Input >= 8000000) c += 8, Input -= 8000000;
else {
if(Input >= 4000000) c += 4, Input -= 4000000;
if(Input >= 2000000) c += 2, Input -= 2000000;
}
if(Input >= 1000000) c += 1, Input -= 1000000;
temp = c;其他的依此类推。 标记一下,高速ltoa算法。 你思路是否有问题,钻牛角尖可不好,仅仅是一个显示在那里瞎折腾,你的项目的数据变化率有多快?是否真的需要那么快才可以满足要求的,1602的显示速率那么低,变化那么快根本看不清有何意义,你计算那么快干嘛。。。脑筋转下弯吧
实在不行可以用16进制显示,这个超快,乘除法都没用到。 takashiki 发表于 2013-2-6 22:06 static/image/common/back.gif
是的,做了近似处理。所以只有最后面的三位采用了乘法+移位方式,前面的没有,因为会有误差。8后必 ...
我不知道怎么算周期,我自己弄了一个这个unsigned char u2s_temp;
unsigned char* ulong_to_str(long int num)
{
//usart_transmit_string("A");
u2s_temp='\0';//结束标记
if(num>89999999) {u2s_temp=9+'0';num=num-90000000;}
else if(num>79999999) {u2s_temp=8+'0';num=num-80000000;}
else if(num>69999999) {u2s_temp=7+'0';num=num-70000000;}
else if(num>59999999) {u2s_temp=6+'0';num=num-60000000;}
else if(num>49999999) {u2s_temp=5+'0';num=num-50000000;}
else if(num>39999999) {u2s_temp=4+'0';num=num-40000000;}
else if(num>29999999) {u2s_temp=3+'0';num=num-30000000;}
else if(num>19999999) {u2s_temp=2+'0';num=num-20000000;}
else if(num> 9999999) {u2s_temp=1+'0';num=num-10000000;}
else u2s_temp=0+'0';
if(num>8999999) {u2s_temp=9+'0';num=num-9000000;}
else if(num>7999999) {u2s_temp=8+'0';num=num-8000000;}
else if(num>6999999) {u2s_temp=7+'0';num=num-7000000;}
else if(num>5999999) {u2s_temp=6+'0';num=num-6000000;}
else if(num>4999999) {u2s_temp=5+'0';num=num-5000000;}
else if(num>3999999) {u2s_temp=4+'0';num=num-4000000;}
else if(num>2999999) {u2s_temp=3+'0';num=num-3000000;}
else if(num>1999999) {u2s_temp=2+'0';num=num-2000000;}
else if(num> 999999) {u2s_temp=1+'0';num=num-1000000;}
else u2s_temp=0+'0';
if(num>899999) {u2s_temp=9+'0';num=num-900000;}
else if(num>799999) {u2s_temp=8+'0';num=num-800000;}
else if(num>699999) {u2s_temp=7+'0';num=num-700000;}
else if(num>599999) {u2s_temp=6+'0';num=num-600000;}
else if(num>499999) {u2s_temp=5+'0';num=num-500000;}
else if(num>399999) {u2s_temp=4+'0';num=num-400000;}
else if(num>299999) {u2s_temp=3+'0';num=num-300000;}
else if(num>199999) {u2s_temp=2+'0';num=num-200000;}
else if(num> 99999) {u2s_temp=1+'0';num=num-100000;}
else u2s_temp=0+'0';
if(num>89999) {u2s_temp=9+'0';num=num-90000;}
else if(num>79999) {u2s_temp=8+'0';num=num-80000;}
else if(num>69999) {u2s_temp=7+'0';num=num-70000;}
else if(num>59999) {u2s_temp=6+'0';num=num-60000;}
else if(num>49999) {u2s_temp=5+'0';num=num-50000;}
else if(num>39999) {u2s_temp=4+'0';num=num-40000;}
else if(num>29999) {u2s_temp=3+'0';num=num-30000;}
else if(num>19999) {u2s_temp=2+'0';num=num-20000;}
else if(num> 9999) {u2s_temp=1+'0';num=num-10000;}
else u2s_temp=0+'0';
if(num>8999) {u2s_temp=9+'0';num=num-9000;}
else if(num>7999) {u2s_temp=8+'0';num=num-8000;}
else if(num>6999) {u2s_temp=7+'0';num=num-7000;}
else if(num>5999) {u2s_temp=6+'0';num=num-6000;}
else if(num>4999) {u2s_temp=5+'0';num=num-5000;}
else if(num>3999) {u2s_temp=4+'0';num=num-4000;}
else if(num>2999) {u2s_temp=3+'0';num=num-3000;}
else if(num>1999) {u2s_temp=2+'0';num=num-2000;}
else if(num> 999) {u2s_temp=1+'0';num=num-1000;}
else u2s_temp=0+'0';
if(num>899) {u2s_temp=9+'0';num=num-900;}
else if(num>799) {u2s_temp=8+'0';num=num-800;}
else if(num>699) {u2s_temp=7+'0';num=num-700;}
else if(num>599) {u2s_temp=6+'0';num=num-600;}
else if(num>499) {u2s_temp=5+'0';num=num-500;}
else if(num>399) {u2s_temp=4+'0';num=num-400;}
else if(num>299) {u2s_temp=3+'0';num=num-300;}
else if(num>199) {u2s_temp=2+'0';num=num-200;}
else if(num> 99) {u2s_temp=1+'0';num=num-100;}
else u2s_temp=0+'0';
if(num>89) {u2s_temp=9+'0';num=num-90;}
else if(num>79) {u2s_temp=8+'0';num=num-80;}
else if(num>69) {u2s_temp=7+'0';num=num-70;}
else if(num>59) {u2s_temp=6+'0';num=num-60;}
else if(num>49) {u2s_temp=5+'0';num=num-50;}
else if(num>39) {u2s_temp=4+'0';num=num-40;}
else if(num>29) {u2s_temp=3+'0';num=num-30;}
else if(num>19) {u2s_temp=2+'0';num=num-20;}
else if(num> 9) {u2s_temp=1+'0';num=num-10;}
else u2s_temp=0+'0';
u2s_temp=num+'0';
return u2s_temp;
}原理应该没有问题,还没有实验
没有乘除法了,就是代码量很大 这个好久以前都讨论过:怎么还在讨论?要学会搜索 ! sprintf王道...
页:
[1]