OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 13615|回复: 9

分享一种对数的计算方法

[复制链接]

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
发表于 2015-8-31 15:16:50 | 显示全部楼层 |阅读模式
一般的编译器都会有math.h函数库给用户提供数学函数的运算,但是也有一些坑爹的编译器没有这个库,而math源文件又是不开源的。有的时候一些项目需要用到对数的计算。楼主在这里分享一种大真数的对数计算方法。
大家都知道可微函数可以用麦克劳林公式展开成幂级数,幂级数就可以在单片机里面用浮点的四则运算来搞了。
比如对数的麦克劳林级数是这样的:


但是这个级数有2个问题,1是只能在x=0附近展开,限制了真数的范围;2是它是个交错级数,收敛比较慢。
所以需要对级数进行变形解决这2个问题。
令y = (x - 1) / (x + 1),则


这样就加快了收敛速度,把x可以称为原真数,y称为变形真数。真数的范围仍然存在限制,x需要靠近1,y需要靠近0.

下面解决真数范围的问题,求ln(z),z是个大真数,就需要对z进行规格化,使规格化后的真数靠近1.
因为对数有这样的关系ln(ab)=lna+lnb,所以能够规格化。
假设z=(10^k0)*(2^k1)*x,   0<x<2;
那么ln(z)=k0*ln(10)+k1*ln(2)+ln(x)  就把真数映射到1附近了,而ln10和ln2可以事先算出来作为常数处理。
这样lnz就能计算了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
 楼主| 发表于 2015-8-31 15:19:01 | 显示全部楼层
[mw_shl_code=c,true]这是c语言的代码 /* 计算一个浮点数的幂函数 */ float FunPower(float bottom_num,u16 exponent) { float power = 1; u16 cnt; for(cnt=0;cnt<exponent;cnt++) { power *= bottom_num; } return power; } /* 计算对数多项式的和,第一个参数是真数变换后的值 * 第二个参数的展开的阶数N */ float LogPoly(float transform,u16 step) { u16 n; float polysum = 0.0; for(n=0;n<step;n++) { polysum += (FunPower(transform,2*n)/(2*n+1)); } return polysum*2*transform; } /* 计算一个浮点数的对数,输入参数是这个浮点数(真数),它应该比1.33大 */ float Logarithm(float antilog) { float log_std = antilog; //规格化后的真数 float log_tran; //对log_std变形后的真数(变形真数) float log_result; //对数的运算结果 s16 log_exp_dec = 0; //对对数规格化的10进制阶码 s16 log_exp_bin = 0; //对对数规格化的2进制阶码 /* 规格化使真数在0.6667和1.3333之间,使他更接近1 */ //第一步模10规,使真数在0.1333到1.3333之间 while(1) { if(log_std<=1.3333) { break; } else { log_std /= 10; //尾数除10 log_exp_dec++; //阶码加一 } } //第二步模2规,使真数在0.6667到1.3333之间 while(1) { if(log_std>=0.6667) { break; } else { log_std *=2; //尾数乘2 log_exp_bin --; //阶码减一 } if(log_std <= 0) { return 0; } } log_tran = (log_std-1)/(log_std+1); //得到的变形真数 log_result = log_exp_dec*LN10 + log_exp_bin*LN02 + LogPoly(log_tran,10); //展开10阶 return log_result; }[/mw_shl_code]

回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2015-8-31 18:04:15 | 显示全部楼层
不错,谢谢分享!!!
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2015-8-31 20:53:40 | 显示全部楼层
高数的 大部分知识已经还给老师了。。。
膜拜下楼主。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

新手上路

积分
20
金钱
20
注册时间
2015-12-27
在线时间
2 小时
发表于 2016-3-15 17:33:29 | 显示全部楼层
楼主函数的第三个是什么意思呢?没怎么看明白啊,感觉只要前两步就足够了啊!
回复 支持 反对

使用道具 举报

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
 楼主| 发表于 2016-3-17 09:48:24 | 显示全部楼层
lizq3531 发表于 2016-3-15 17:33
楼主函数的第三个是什么意思呢?没怎么看明白啊,感觉只要前两步就足够了啊!

麦克劳林级数只能在0附近展开,像ln(65535)这种大真数的对数是不能直接用的,需要把真数变换到0附近,1楼有说明
回复 支持 反对

使用道具 举报

0

主题

9

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2015-8-8
在线时间
3 小时
发表于 2016-3-17 09:59:26 | 显示全部楼层
真是不错啊
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手入门

积分
14
金钱
14
注册时间
2017-7-23
在线时间
0 小时
发表于 2017-7-28 13:54:15 | 显示全部楼层
log_poly计算可以再优化,对于1+1/3*x^2+1/5*x^4+...+1/(2n-1)*x^(2n)可以利用迭代
1+x^2*(1/3+x^2*(1/5+....+x^2*1/(2n-1))...),这样可以大量减少乘法次数
回复 支持 反对

使用道具 举报

2

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2017-11-5
在线时间
3 小时
发表于 2018-3-14 23:53:37 | 显示全部楼层
楼主,那像 y=1234x^(-1.234)这样的幂指数 用STM32可以实现吗?
回复 支持 反对

使用道具 举报

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
 楼主| 发表于 2018-3-15 10:19:48 | 显示全部楼层
sMathew 发表于 2018-3-14 23:53
楼主,那像 y=1234x^(-1.234)这样的幂指数 用STM32可以实现吗?

c标准库math.h 里有函数 extern _ARMABI double pow(double /*x*/, double /*y*/);
库里面还有很多别的函数,包括log等等。

用keil的话直接调用就行,可以用stm32计算幂指数。

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 05:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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