OpenEdv-开源电子网

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

float型全局变量和全局常量,用于数据计算时的处理速度为什么会不一样?有什么办法解决速度问题?

[复制链接]

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
发表于 2020-12-24 10:42:15 | 显示全部楼层 |阅读模式
1金钱
代码中有float y....float x


#define   aaa   1.4
float y;
y = 1.1 * 1.2 + 1.3 * 1.4;或y = 1.1 * 1.2 + 1.3 * aaa;
这两种写法的执行时间都为30us左右。


float y;
float x = 1.4
y = 1.1 * 1.2 + 1.3 * x;
这种写法执行时间为300us左右。

请问各位大佬
1、为什么这两种处理的时间会差这么大?就因为一个取变量,一个取常量?
2、我这个x是用于数据迭代的,所以只能是变量,还有任何办法让它的速度跟常量一样吗?

自在随心
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

141

帖子

0

精华

高级会员

Rank: 4

积分
679
金钱
679
注册时间
2020-11-21
在线时间
67 小时
发表于 2020-12-24 12:57:22 | 显示全部楼层
把小数先转换成整数,计算完成后在转成小数。
回复

使用道具 举报

12

主题

3387

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8633
金钱
8633
注册时间
2020-5-11
在线时间
4074 小时
发表于 2020-12-24 13:58:13 | 显示全部楼层
编译器若有优化,可能在编译时就把结果算好了,程序到时只需赋值而无需计算过程。
如非必要,不要用浮点运算,用整数代替小数,如123代替1.23,只需要在需要显示的时候显示出一个小数点即可。
专治疑难杂症
回复

使用道具 举报

1

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
388
金钱
388
注册时间
2020-11-7
在线时间
44 小时
发表于 2020-12-24 15:06:56 | 显示全部楼层
本帖最后由 游走在01的海洋 于 2020-12-24 15:16 编辑

我是从CPU去内存中存取数据这个角度来看的。首先要明确一点:CPU执行指令的速度远远大于CPU从内存中存取数据的速度;所以在CPU执行指令的时间远远小于CPU从内存中存取数据的时间。

再看代码:
#define aaa 1.4 是宏定义,在代码预编译期间,就会将宏定义的值1.4替换aaa;换言之,y = 1.1 * 1.2 + 1.3 * 1.4;或y = 1.1 * 1.2 + 1.3 * aaa;这两条代码在CPU执行时是没有区别的。


但是:y = 1.1 * 1.2 + 1.3 * x;这条指令中x是个变量,内容存储在内存中,所以CPU执行到这里的时候会有一个去内存“取值”的过程,从而导致处理时间加长。

回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2020-12-24 17:20:02 | 显示全部楼层
本帖最后由 ufbycd 于 2020-12-24 17:21 编辑

常量时,y值在编译时就已经确定,运行时没有计算过程;
变量时,y值只能在运行时确定,运行时就有计算过程。
编译器开不开优化都会是这样。

回复

使用道具 举报

22

主题

2251

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4477
金钱
4477
注册时间
2013-4-22
在线时间
336 小时
发表于 2020-12-24 18:30:41 | 显示全部楼层
你的研究下预编译就知道为什么了
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2020-12-24 18:38:52 | 显示全部楼层
会差一点, 但不可能差10倍, 换个编译器版本试试吧
难道用的是51?
回复

使用道具 举报

15

主题

172

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1276
金钱
1276
注册时间
2016-5-31
在线时间
499 小时
发表于 2020-12-24 20:44:19 | 显示全部楼层
//请注意:作为浮点数计算,你一定要在小数后面加数据类型符号'f',
//不然编译器默认按照:double数据类型计算,程序那就会执行较长的时间!!!
//不信的话,请试试下面的函数,执行速度就会很快!
float  float_function(void)
{       
        float y=0.0f;
        float x = 1.4f;
       
        y = 1.1f * 1.2f + 1.3f * x;
       
        return y;
}
回复

使用道具 举报

5

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
137
金钱
137
注册时间
2017-5-20
在线时间
30 小时
发表于 2020-12-25 09:04:19 | 显示全部楼层
第一个y,在编译的时候就确定具体的值,相当于写y=xxx.xxx ;
第二个y,需要mcu运行,计算。差10倍不算什么。
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2020-12-25 11:23:53 | 显示全部楼层
winuc 发表于 2020-12-25 09:04
第一个y,在编译的时候就确定具体的值,相当于写y=xxx.xxx ;
第二个y,需要mcu运行,计算。差10倍不算什么。

可否说详细点, 这多出来的9倍时间, CPU都做了些啥吗?
回复

使用道具 举报

3

主题

2178

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3323
金钱
3323
注册时间
2013-7-19
在线时间
195 小时
发表于 2020-12-25 12:17:14 | 显示全部楼层
本帖最后由 ricefat 于 2020-12-25 12:26 编辑
edmund1234 发表于 2020-12-25 11:23
可否说详细点, 这多出来的9倍时间, CPU都做了些啥吗?

第一条运行过程根本不需要算,程序编译时候就有结果了,结果已经写到了FLASH,用的时候直接读取结果到sram就行。
第二条是要把中间变量的值从flash拿到SRAM,再拿到CPU去计算,结果再送回SRAM,而乘法和除法本身就需要更长的运算时间。
8位51单片机ADD加法指令需要1个机器周期,而乘除法需要4个机器周期,而前面将flash内容搬运到RAM需要2个机器周期,时间能相差一倍,如果是多字节乘除会差距更大。
32位的应该也是类似的原因。
回复

使用道具 举报

5

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
137
金钱
137
注册时间
2017-5-20
在线时间
30 小时
发表于 2020-12-25 16:35:49 | 显示全部楼层
edmund1234 发表于 2020-12-25 11:23
可否说详细点, 这多出来的9倍时间, CPU都做了些啥吗?

我觉得你需要学习一些汇编的知识,之后就会明白了。
回复

使用道具 举报

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
 楼主| 发表于 2020-12-28 16:08:48 | 显示全部楼层
edmund1234 发表于 2020-12-24 18:38
会差一点, 但不可能差10倍, 换个编译器版本试试吧
难道用的是51?

不好意思,这些天在弄代码,公司没有网不方便上论坛。
现用的MSP430,目前要求主频只能限4M和32768,RAM只有2K,所以得省吃简用的。
我想做一个低通滤波的东西,函数在STM32里测试过可用,就开始移植了,单纯想试试MSP430能不能负担的起来。
现在是有几个情况想继续说明一下和问一下:
1、网上说浮点乘除法运算慢,基至2000个机器周期。。。。。这个我测试好像double型的确实将近2000个周期。float型的可能在100个周期左右。
2、比较有意思的一点是,我实测了一下各种运算的耗时,发现float型乘法1.4*AAA,用了110个机器周期。而1.3+AAA用了200个机器周期。也就是说加法比乘法运算还要慢一倍???这我就很诧异了。。。什么原因导致的?不应该是乘法慢吗?我找了好久都没发现任何其它问题。
3、大家从来都说不要用浮点运算,包括我用STM32这么多年,浮点运算上也吃过不少亏。一个原因是运算速度慢。另一个更主要的原因是它会导致工程中某些数据莫名其妙出错。我一直怀疑是硬件原因,浮点数据占用的位置溢出导致的,又不是我们写代码的问题。
但是,重点是,试了MSP430后发现,代码里到处都在用float,没有任何地方出错,我自己试着加代码,也没出错。。。这又很诧异了,数据容易出错,难道是STM32自己不稳定导致的问题?
4、代码优化等级的事,以前用STM32觉得自己没那么NB,所以从来不敢开优化,也没研究过优化功能。现在为了节省资源,不得不优化了。请问这优化都搞了啥了,为啥明明对的逻辑优化后就错了。。。
举个例子
不加优化:
for(i = 0;i <2;i++),执行起来没错,最后i会变成2。
for(i = 0;i < 200;i = i + 110),执行起来也没错,最后会变成220.
加优化
for(i = 0;i <2;i++),执行起来没错,最后i会变成2。
for(i = 0;i < 200;i = i + 110),执行起来不对,最后会变成110.而且不是每次执行完都是110,可能
自在随心
回复

使用道具 举报

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
 楼主| 发表于 2020-12-28 16:09:42 | 显示全部楼层
ricefat 发表于 2020-12-25 12:17
第一条运行过程根本不需要算,程序编译时候就有结果了,结果已经写到了FLASH,用的时候直接读取结果到sra ...

大佬请看前一楼,继续问了点儿问题
自在随心
回复

使用道具 举报

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
 楼主| 发表于 2020-12-28 16:29:07 | 显示全部楼层
三叶草 发表于 2020-12-24 18:30
你的研究下预编译就知道为什么了

你好,请教一下,我一直认为预编译只要扩展开#define,并不会做计算,如果预编译可以做计算的话,做1.1*1.2*1.3*AAA,或是做1.1*AAA,其中AAA为变量,首先是不是处理时间不会变,但实际上它是在变的。1.1*1.2*1.3*AAA耗费了更多时间。
另外如果1.1*1.2*1.3*AAA/2.3/2.4,它会怎么做?总不能是留下AAA,而先把其它的都算完吧,所以是不是可以这么说,一句代码里如果带变量它在预编译时就不会预先计算?如果全是常量就会预先算完?

另外想问一下,这个事如果带上代码优化,优化等级选最高,有没有可能它真的把1.1*1.2*1.3/2.3/2.4先算完了。。。那我的数岂不是没按预想的来实现,怕是多少会损失精度吧。
期待解答
自在随心
回复

使用道具 举报

56

主题

343

帖子

0

精华

高级会员

Rank: 4

积分
977
金钱
977
注册时间
2016-3-8
在线时间
267 小时
发表于 2020-12-29 00:17:19 | 显示全部楼层
yuzeyuan1 发表于 2020-12-28 16:29
你好,请教一下,我一直认为预编译只要扩展开#define,并不会做计算,如果预编译可以做计算的话,做1.1*1 ...

如果AAA是常量,预处理就会计算完,计算出的常量精度看常量有没有修饰。没修饰编译器默认来。如果是变量,编译器会评估预处理会不会影响结果。进行部分预处理或不预处理。
回复

使用道具 举报

22

主题

2251

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4477
金钱
4477
注册时间
2013-4-22
在线时间
336 小时
发表于 2020-12-29 09:01:21 | 显示全部楼层
yuzeyuan1 发表于 2020-12-28 16:29
你好,请教一下,我一直认为预编译只要扩展开#define,并不会做计算,如果预编译可以做计算的话,做1.1*1 ...

其实预编译的时候就已经把那部分常量计算好了,这样效率才高的。其实这是典型的用空间换时间的方式之一。
回复

使用道具 举报

33

主题

215

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2033
金钱
2033
注册时间
2017-12-11
在线时间
454 小时
发表于 2020-12-29 09:16:44 | 显示全部楼层
不可能有这么长时间吧,你是否只是给出了部分代码。
我也使用430,我跑8M主频,没发现什么问题呀。
请注意:例如,1.2,这不是float类型,系统默认是double类型。如果你想把它改为float类型,请务必使用1.2f。
回复

使用道具 举报

28

主题

294

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1790
金钱
1790
注册时间
2018-3-26
在线时间
294 小时
发表于 2020-12-29 09:22:36 | 显示全部楼层
小数1.3,不是1.3f ,是double型吧,强转再计算, 计算有300us的话,应该有问题吧。之前在f4系列上,测试过,好像是几百次运算才几ms,然后尽量多用 加减, 少用乘,更要少用除法。
茵茵猪头
回复

使用道具 举报

80

主题

931

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3348
金钱
3348
注册时间
2013-5-28
在线时间
468 小时
发表于 2020-12-29 11:17:50 | 显示全部楼层
htao 发表于 2020-12-29 09:22
小数1.3,不是1.3f ,是double型吧,强转再计算, 计算有300us的话,应该有问题吧。之前在f4系列上,测试过 ...

他主频才4M....
回复

使用道具 举报

80

主题

931

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3348
金钱
3348
注册时间
2013-5-28
在线时间
468 小时
发表于 2020-12-29 11:20:52 | 显示全部楼层
yuzeyuan1 发表于 2020-12-28 16:08
不好意思,这些天在弄代码,公司没有网不方便上论坛。
现用的MSP430,目前要求主频只能限4M和32768,RAM ...

用TI的MSP430,请不要用常规思维,会死的难看的,原因有以下几点:
1.芯片设计时好像是在2000年左右,反正上市好像就2005
2.MSP430为了省电,省了很多逻辑单元,我做到最低的电流是0.5uA,确实没什么想法了
回复

使用道具 举报

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
 楼主| 发表于 2020-12-29 16:20:01 | 显示全部楼层
htao 发表于 2020-12-29 09:22
小数1.3,不是1.3f ,是double型吧,强转再计算, 计算有300us的话,应该有问题吧。之前在f4系列上,测试过 ...

13楼有断长的文字,其中第二条就很奇怪,我实测效果是加法比乘法要更耗时,想不通为什么
自在随心
回复

使用道具 举报

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
 楼主| 发表于 2020-12-29 16:25:26 | 显示全部楼层
聚东风 发表于 2020-12-29 11:20
用TI的MSP430,请不要用常规思维,会死的难看的,原因有以下几点:
1.芯片设计时好像是在2000年左右,反正上 ...

恩呢,430的低功耗真是思料之外的舒服。
430常规应该也是用在表体上吧?在室外一放就是十年那种。
但是我感觉,表体终归是要做一些计算处理的,至少在浮点运算这块,430做的也是相当的稳定
自在随心
回复

使用道具 举报

84

主题

766

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2775
金钱
2775
注册时间
2015-6-1
在线时间
394 小时
 楼主| 发表于 2020-12-29 16:32:46 | 显示全部楼层
bootblack 发表于 2020-12-29 09:16
不可能有这么长时间吧,你是否只是给出了部分代码。
我也使用430,我跑8M主频,没发现什么问题呀。
请注 ...

代码的话,我其实只是在用430做个测试,顺便看看性能,所以代码除了驱动和几个for循环处理几个加法乘法,再没别的东西。正常跑代码确实没什么问题,但是我现在是想加一个数据迭代处理,每次迭代都是一阶滤波,几十个us就想进行一次迭代。所以整出来一堆麻烦事。

我现在改用了8M,确实效果好了非常多。。。

1.2f这个东西,我目前是在用的。

自在随心
回复

使用道具 举报

33

主题

215

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2033
金钱
2033
注册时间
2017-12-11
在线时间
454 小时
发表于 2020-12-29 18:34:14 | 显示全部楼层
yuzeyuan1 发表于 2020-12-29 16:32
代码的话,我其实只是在用430做个测试,顺便看看性能,所以代码除了驱动和几个for循环处理几个加法乘法, ...

想办法优化你的代码。
我也是使用430做仪表,而且我的表其实功能也很多,上一个工程师用stm32跑72M主频都说慢。
但是我用8M主频同样也能满足需求,并且并不慢。
总结下来,尽可能优化你的代码。
备注:之所以用8M主频,归根到底还是降低功耗,我的这款芯片最低是跑8M主频。
回复

使用道具 举报

9

主题

251

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1366
金钱
1366
注册时间
2014-11-25
在线时间
185 小时
发表于 2020-12-30 08:55:53 | 显示全部楼层
define是一种替换式的,并非定义变量,我记得直接写进了code区了,也就是norflash,float多一个开辟内存在sram里,处理上define是在编译时,float是在运行时!!!!!
回复

使用道具 举报

10

主题

205

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1322
金钱
1322
注册时间
2015-3-3
在线时间
127 小时
发表于 2020-12-30 11:41:45 | 显示全部楼层
为了速度,我一般都会扩大N+1倍,计算完成后在缩小之前检查最后一位是大于5还是小于5,做进位判断,然后再缩小回原来的位数即可.
海纳百川者,荣耀伴一生!
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-15 10:54

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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