用IAR开发MSP430,64位除法,占时太长,有没有好办法?
本帖最后由 hzpyl 于 2017-5-22 09:28 编辑用IAR开发MSP430,64位除法,占时太长,对低功耗不利
MSP430时钟4.9152MHZ
下面一个除法,占时1.5ms
一个余数,占时1.1ms
有没有好办法?
u32 heat_power(u32 dt,u32 *dtl,u16 tmper_drop)
{
u64temp64;
u32temp32A, temp32B;
temp64 = (u64)dt *tmper_drop *5015 ; // 运行330us
temp64 += *dtl; //加上上次的尾数(余数)
temp32A = temp64/ 2500000; // 运行1.5ms
temp32B = temp64% 2500000; // 运行1.1ms
*dtl = temp32B; //保存尾数(余数)
return(temp32A);
}
补充:
用减法与乘法代替,求余数
temp32A = temp64 /2500000; // 运行1.5ms
temp32B = temp64 - (temp32A*2500000); // 运行0.05ms
补充:
修改注释:
//加上上次的尾数(余数)
//保存尾数(余数)
为了不使用浮点数,且尽可能提高精度,每次计算都保留余数,下次计算再加上余数。
改成乘移位吧。要不然就超频。除法只能对bit操作,考虑64位,需要做64*4次比较,64*4次减法,64*65次移位,还是很慢的。 这里有LZ需要的一切脑洞
http://blog.csdn.net/lggrief/article/details/52796400 可以试试有没有lldiv库函数,可以同时求出商和余,时间能少一些。64位运算对16位的msp430有压力,想办法减小数据类型 Nuker 发表于 2017-5-20 11:28
这里有LZ需要的一切脑洞
http://blog.csdn.net/lggrief/article/details/52796400
谢谢你。
我用减法与乘法代替,求余数
temp32A = temp64 /2500000; // 运行1.5ms
temp32B = temp64 - (temp32A*2500000); // 运行0.05ms 瑞萨的产品没有用大位数的除法。
没有试。 提供个思路看是否可行,列个表,2500000的10的n次方倍一直到64位的最大值,然后从大往小减,这样就只有加减和比较,不知道速度怎么样 IAR 怎样设置,可以只计算除法一次,得到商和余数? 除法也可以转成乘法 应该会更快 整数除法可以用减法循环啊,当然很可能汇编代码就是这么做的 hzpyl 发表于 2017-5-20 20:53
IAR 怎样设置,可以只计算除法一次,得到商和余数?
测试程序来了{:lol:}
没找到板子,stm32f1软件仿真,随便取了个数测试
从结果上来看减法的方法比除法慢,
16位机子就不知道哪个快了,你可以试下{:lol:}
void test(void)
{
register unsigned long long u64_temp = 10737418237500000ULL;
register unsigned long u32_tempA = 0;
register unsigned long u32_tempB = 0;
u32_tempA = u64_temp / 2500000;
u32_tempB = u64_temp - u32_tempA * 2500000; //0.0000324
u32_tempA = 0;
while(u64_temp >= 2500000 * 1000000000ULL)
{
u64_temp -= 2500000 * 1000000000ULL;
u32_tempA += 1000000000UL;
}
while(u64_temp >= 2500000 * 100000000ULL)
{
u64_temp -= 2500000 * 100000000ULL;
u32_tempA += 100000000UL;
}
while(u64_temp >= 2500000 * 10000000ULL)
{
u64_temp -= 2500000 * 10000000ULL;
u32_tempA += 10000000UL;
}
while(u64_temp >= 2500000 * 1000000ULL)
{
u64_temp -= 2500000 * 1000000ULL;
u32_tempA += 1000000UL;
}
while(u64_temp >= 2500000 * 100000ULL)
{
u64_temp -= 2500000 * 100000ULL;
u32_tempA += 100000UL;
}
while(u64_temp >= 2500000 * 10000ULL)
{
u64_temp -= 2500000 * 10000ULL;
u32_tempA += 10000UL;
}
while(u64_temp >= 2500000 * 1000ULL)
{
u64_temp -= 2500000 * 1000ULL;
u32_tempA += 1000UL;
}
while(u64_temp >= 2500000 * 100ULL)
{
u64_temp -= 2500000 * 100ULL;
u32_tempA += 100UL;
}
while(u64_temp >= 2500000 * 10ULL)
{
u64_temp -= 2500000 * 10ULL;
u32_tempA += 10UL;
}
while(u64_temp >= 2500000 * 1ULL)
{
u64_temp -= 2500000 * 1ULL;
u32_tempA += 1UL;
}
u32_tempB = (unsigned long)u64_temp; //0.0001235
u32_tempA += u32_tempB;
}
啥电池,1ms也要省。如果没有硬件浮点的话,应该移位加小位数乘还是比乘法要快把 这个好简单哦,我抛块砖,LZ是捡到了玉,还是被砸成了脑震荡,我都不管。 temp32A = temp64 / 2500000
= temp64 * (2^64) / 2500000 >> 64
= temp64 * 7378697629484 >> 64
= temp64 * 3602879701 << 11 >> 64
= temp64 * 3602879701 >> 53最后的结果是有误差的,商和上面计算结果相差应该在-1、0、1之间。至于64bit * 64bit、128bit移位这么简单的东西就自己解决吧。 takashiki 发表于 2017-5-21 05:55
这个好简单哦,我抛块砖,LZ是捡到了玉,还是被砸成了脑震荡,我都不管。最后的结果是有误差的,商和上面计 ...
谢谢。
我验算一下。 Ray______ 发表于 2017-5-20 22:47
啥电池,1ms也要省。如果没有硬件浮点的话,应该移位加小位数乘还是比乘法要快把 ...
每500ms计算一次,多1ms,影响功耗 用近似法不行嗎 搞到64位 那麼精準 該不是做彈道吧 先優化目標算法 再寫程序 不然就得上64CPU才行 takashiki 发表于 2017-5-21 05:55
这个好简单哦,我抛块砖,LZ是捡到了玉,还是被砸成了脑震荡,我都不管。最后的结果是有误差的,商和上面计 ...
你这个让楼主用long long都不行錒,128位长的数据,单片机编译器不支持 NJ8888 发表于 2017-5-21 11:29
你这个让楼主用long long都不行錒,128位长的数据,单片机编译器不支持
单片机当然不支持,能够支持long long就已经相当相当不错了。好多单片机还根本不支持64位数据呢。
不过这么简单的问题就不用继续深入讨论了,用联合体啥的交叉相乘就出结果了,也就几个long * long的乘法 + 几个long long的加法,LZ很容易就会搞出来了。 可能能查表分支降低 takashiki 发表于 2017-5-21 17:59
单片机当然不支持,能够支持long long就已经相当相当不错了。好多单片机还根本不支持64位数据呢。
不过这 ...
用联合体啥的交叉相乘就出结果了,也就几个long * long的乘法 + 几个long long的加法,
请问,大神,这样写?
14楼的,我验证了,有误差,其误差影响精度。 hzpyl 发表于 2017-5-22 08:22
用联合体啥的交叉相乘就出结果了,也就几个long * long的乘法 + 几个long long的加法,
请问,大神,这 ...
自己搜索解决方案去,我不会什么都给你做好的。提示:小学时候计算12 * 15列竖式是怎么算的,中学时候(a+b)(c+d)是怎么算的,如果说的这么明白还理解不了的话,那我抛下砖,得赶紧撒丫子跑。或者你当RMB玩家充个VIP就会一飞冲天,我会完满解决你的需求的。不过你放心,我所谓完满解决所花的时间肯定只会比我现在提的方法更少,因为要进行专门的优化而不是像现在这样的通解。
有误差是必须的,影响精度是肯定的。所以你要对这个计算出来的结果稍微进行处理一下啊。比如余数 = 被除数 - 商 * 250000; while(余数 < 0){ 余数 += 250000; 商--;}之类的。不细说了,命中的概率极低,但会有,基本上不怎么消耗时间。
事实上,从你的temp32A = temp64/ 2500000; // 运行1.5ms
temp32B = temp64% 2500000; // 运行1.1ms就可以看出来,你的最终结果其实就只有几个unsigned long的乘法 + 几个unsigned long的加法而已,连64位都不用。 除数为2500000不变吗?不变的话可以转化为乘法。
1/2500000=(0x06b5)/(0x100000000) myxiaonia 发表于 2017-5-20 22:20
整数除法可以用减法循环啊,当然很可能汇编代码就是这么做的
如果 一个64位数 除以 3 那不知道 要减多少次,这样肯定快不了 你搞定了吗?
我最近也碰到这个问题
大致 找到三种方法
1. 试商法
2.移位相减法
3.迭代法这个算法需要用到64位 乘法 也要用快速方法
暂时没测试哪一种更快主要还有一个近似性 如果相同的结果 看运算速度了
转别人的文章一个: 迭代法 算的
---------------------------------------------------------------------------------------------------
上一篇文章讲到了估商法的原理,有了一个不错的效率,但在要求精度较大时,速度和迭代法相比差距很大。
除法:u/y=u*(1/y);
先讲一下倒数迭代式:x1=(2-y*x0)*x0,x0是y的倒数的近似值,它必须要小于y的倒数。另外迭代式中的乘法子程序要选用快速乘法(如FFT算法的乘法子程序)。
否则迭代法的除法速度是很慢的,远远小于估商法。
以求9的倒数为例演示迭代法的使用,求9的32精度的倒数:
1/9=1.1111111111111111111111111111111e-1;这里计算的是9的32位精度的倒数
(2-9*0.11)*0.11=1.111e-1; 现在我们用初值0.11迭代计算32位精度的倒数
(2-9*0.1111)*0.1111=1.1111111e-1;
(2-9*0.11111111)*0.11111111=1.111111111111111e-1;
(2-9*1.111111111111111e-1)*1.111111111111111e-1 = 1.1111111111111111111111111111111e-1;
对于如何确定y的初值,网上找不到相关的文献,我最早是有估商法算y的前N位的初值,然后迭代算出精度更高的倒数。
但是这种方法在综合运算时,估商法存在大量的进制转换,和指数对位,效率不高。
前一段时间才实破用计算器的cpu的除法功能计算除数倒数的初值,这个问题原理很简单,实现起来还是相当复杂的,三分的算法原理,七份的调试。
注:这里计论的都是有理数,不是正整数(只能对正整数加减乘除的子程序进行综合运算时是相当费时费力的,并且很难保证正确性)!
利用cpu 算初值,由于cpu除法的局限性,过小的或过大的数它都计算不了,所以这些数你必须调整规范为0.xxx...*10^n的形式,其中xxx必须为有效数字,1234可以表示为0.1234*10^4,但不能为0.01234*10^5,这都是调试才能理解的技术,不调试你很难理解,
选取除数的前几个有效数字用cpu算倒数,这里是8.1037277147487844408427876823339e-4,cpu算出的倒数你还必须识别并换算成高精度数的表示形式,才能进行后面的迭代运算,后面的迭代运算需要有理数的加,减,乘支持。
纯迭代法实现的除法代码更简洁,效率更高,特别是作为子程序调用时可以减少一些中间转换,在综合运算中效率是估商配迭代法的一倍左右。
还有这个算法 我没看懂
//被除数 S除数 X
u32 div(u64 s,u32 z) //s/z//y保存商 quotient x保存余数 remainder
{
u32 i;
u32 x=(u32)(s>>32);
u32 y=(u32)s;
if (z==0)return 0;
for (i=0;i<32;++i)
{
u32 t=((s32)x) >> 31;
x=(x<<1)|(y>>31);
y=y<<1;
if ((x|t) >= z)
{
x -= z;
++y;
}
}
return y;
} 当年天文学家们搞轨道计算的时候也遇到大数乘除法计算太慢的问题。当年距离计算机发明还有几百年。后来想出来的解决方法是发明了对数表,把乘除运算转换为加减运算。 问个题外话,楼主这个平均功耗是多少 Ray______ 发表于 2017-8-16 02:00
问个题外话,楼主这个平均功耗是多少
液晶显示,功耗<5uA,不算隔几秒计算一次的功耗 稳态小于5ua,niubility,现在一款仪表,fr4133,lcd显示,开了些中断,内核部分20ua了,话说,可以小窗口个lcd的厂家哈。谢谢 fiddly 发表于 2017-8-16 20:24
稳态小于5ua,niubility,现在一款仪表,fr4133,lcd显示,开了些中断,内核部分20ua了,话说,可以小窗口 ...
20uA,肯定是你的程序有问题。
我也是fr4133。
液晶显示的内容多少,影响小于2uA 研发过静态1ua,动态180ua的数据采集,但最后还是嫌功耗大放弃了。 carryonli 发表于 2017-8-17 07:40
研发过静态1ua,动态180ua的数据采集,但最后还是嫌功耗大放弃了。
动态功耗要小,就要减少运算时间。 hzpyl 发表于 2017-8-17 07:36
20uA,肯定是你的程序有问题。
我也是fr4133。
液晶显示的内容多少,影响小于2uA ...
好,我用的是56脚的,8com的液晶片,
方便给个最低功耗小demo不,啥都不干的,我的环境是iar,谢谢
这个算法搞好没 没有找到更好的办法。 hzpyl 发表于 2017-8-17 08:53
动态功耗要小,就要减少运算时间。
不行啊,模拟量采集,AD一启动电流就上来了。再加上后面运算,必须是低速运算,但时间长,电流无法低下来。 takashiki 发表于 2017-5-21 05:55
这个好简单哦,我抛块砖,LZ是捡到了玉,还是被砸成了脑震荡,我都不管。最后的结果是有误差的,商和上面计 ...
哇,确实是抛砖引玉!但是我只有一样大的砖,扔出来试试
a/2500000
= a*(2^64+1)/2500000
= a*7378697629483.82
在直接忽略溢出的情况下成立。误差也好估计,0.18/7378697629483.82=1/40992764608243.445
页:
[1]