嵌入式代码优化(C语言)

优化方法:

1、二维数组相比一维数组存储

2、整数运算相比浮点运算

3、乘除法和移位运算

左移1位相当于乘2,右移1位相当于除2

4、查表运算

比如计算cos sin 函数

例如:

5、并行计算

充分利用ALU单元,在循环内写多次相同的语句,但该数据不能有依赖

这点在STM32F4的CMSIS库的常规数学运算中有相应的示例也是如此操作

6、调用子函数和内联函数

  将函数声明为inline,编译器会将该函数嵌入到母函数中,减少调用子函数的开销 

在CC2640上确实会出现这样的情况:例如在子函数中定义一个256大小的数组,然后运算,那么调试过程中会卡住。

原因可能是:调用该子函数进行大的运算量操作会占用很大计算开销,当改成在主函数中定义,就能解决(实际操作过)

7、对于不同的数据采用恰当的数据类型

 int 32位   

unsight short 16位 0-65535

short 16位 -32768~+32768

uint8_t 8 8位无符号 0-255

char -128-127  uchar 0-255

有符合和无符号,位数区分,整形和浮点

选择的原则是够用即可!

举例:实际操作时采用的比较大的数据类型int类型,进行乘除法的运算出错,后续将数据类型更改后,(浮点运算的优化,将多个已知的乘除法预先计算出来等)得出正确的结果

8、浮点运算 double 和float 型的选择

在浮点数后加上 f,转换为float 型运算, 比如3.0f

因为float 4字节 32 位 ,double 8字节 64 位

关于float 型和double型的位数及小数点位数的表示

参考【3】

浮点数在内存中的存储方式。浮点数,区别于定点数,指的是小数点位不确定的的数据类型,其原理是将一个浮点数a用两个数m(尾数)和e(指数)来表示:a = m × b^e。其中的b为选取的基数。科学计数法就是一种特殊形式的浮点数。

  在计算机二进制表示中,浮点数采用2作为基数,规定尾数的范围为1.0~2.0之间。

 以float类型为例,根据最广泛采用的IEEE754标准规定,float数据类型长度为32位,其中最高位为符号位,中间8位为指数位,最后23位作为尾数位。

  最高位符号位通过0/1来区分正负,0正1负;指数位则规定采用移码的形式存储,这样可以保证指数部分为无符号数,方便比较大小。移码表示法是在数X上增加一个偏移量来定义的,如果机器字长为n,规定偏移量为2^(n-1),对于8位补码-128~127,可得到对应的阶码表示为0~255,其中0和255分别用来表示0和无穷大,1~254用来表示规范数字,即指数范围从-126到127;尾数部分统一规定为1.0-2.0之间,最高位必然为1,故可以省略,所以尾数部分从小数点后算起,最小可以取到1,最大则取到二进制1.1...1(小数点后23位),即取到2-2^-23,可近似约等于2。故得到float绝对值的最大值取到2^127*(2-2^-23)约等于2^128=3.4E+38。加上符号之后可得float表示范围为(-3.4E+38)~(3.4E+38)。当然实际是取不到的,开区间。绝对值最小则可以取到2^-127*1,即为1.175E-38。

接下来解释精度。由于尾数部分位数是固定的小数点后23位,23位所能表示的最大数是2^23−1=8388607,所以十进制的尾数部分最大数值是8388607,也就是说尾数数值超过这个值之后,float将无法精确表示,所以float最多能表示小于8388607的小数点后7位,但绝对能保证的为6位,也即float的十进制的精度为为6~7位

double数据类型的推算过程和上述同理,唯一的区别在于尾数由23位扩展到52位,阶码由8位增加到了11位,计算方法不变。所以double的阶码(移码表示)为0~2047,偏移量为1024,故指数范围为-1024~1023,得表示范围为(2^1023*2)~(-2^1023*2)即为-1.7E+308~1.7E+308,绝对值最小可以取到2^-1024,精度则为2^52-1=4503599627370495,为16位。所以精度最高位16位,一定可以保证15位

原文链接:https://blog.csdn.net/black_kyatu/article/details/79257346

参考:C/C++ float与double的有效数字位 https://blog.csdn.net/VonSdite/article/details/76575247 

9 、查表数据放置在CPU 高速CACHE中

10、把函数用汇编语言编写

11、 调用其它人优化好的库函数,比如成熟的ARM芯片的DSP运算

有两种方法处理:

1、调用library库,并加载,但要设置相关的参数比如代码设置、编译控制等

2、可以直接加载相应的头文件(.h)和源文件(.c),主要是加载armmath.h头文件,并添加相应的要处理的处理源函数,需要注意的是头文件之间的依赖关系。确保能充分无误的#include

1、BasicMathFunctions
提供浮点数的各种基本运算函数,如加减乘除等运算。对于M0/M3只能用Q运算(实际操作在CC2640R2中也可以使用浮点类型的计算,也即是f32开头的,应该是预编译指令自动转换了),即文件夹下以_q7、_q15和_q31结尾的文件;而M4F能直接硬件浮点计算,属于文件夹下以_f32结尾的文件。
2、CommonTables
arm_common_tables.c文件提供位翻转或相关参数表。
3、ComplexMathFunctions
复述数学功能,如向量处理,求模运算的。
4、ControllerFunctions
控制功能,主要为PID控制函数。arm_sin_cos_f32/-q31.c函数提供360点正余弦函数表和任意角度的正余弦函数值计算功能。

5、FastMathFunctions
快速数学功能函数,提供256点正余弦函数表和任意任意角度的正余弦函数值计算功能,和Q值开平方运算:
Arm_cos_f32/_q15/_q31.c:提供256点余弦函数表和任意角度余弦值计算功能。
Arm_sin_f32/_q15/_q31.c:提供256点正弦函数表和任意角度正弦值计算功能。
Arm_sqrt_q15/q31.c:提供迭代法计算平方根的函数。对于M4F的平方根运算,通过执行VSQRT指令完成。

6、FilteringFunctions
滤波函数功能,主要为FIR和LMS(最小均方根)滤波函数。
7、MatrixFunctions
矩阵处理函数。

8、StatisticsFunctions
统计功能函数,如求平均值、计算RMS、计算方差/标准差等。
9、SupportFunctions
支持功能函数,如数据拷贝,Q格式和浮点格式相互转换,Q任意格式相互转换。

10、TransformFunctions
变换功能。包括复数FFT(CFFT)/复数FFT逆运算(CIFFT)、实数FFT(RFFT)/实数FFT逆运算(RIFFT)、和DCT(离散余弦变换)和配套的初始化函数。

官网:

CMSIS-DSP  Version 1.7.0

CMSIS DSP Software Library

http://www.keil.com/pack/doc/CMSIS/DSP/html/index.html

下载该库的方法:到keil官网下载keil5安装包,完成后有库所在的文件路径如下所示:

参考资料:

【1】让你的软件飞起来https://wenku.baidu.com/view/1fb647bdf121dd36a32d8290.html

【2】让你的软件飞起来-----算法优化(整理版)  https://www.cnblogs.com/fhyfhy/p/4452941.html

【3】准确详解:C/C++ float、double数据类型的表示范围及精度 https://blog.csdn.net/black_kyatu/article/details/79257346

【4】 C/C++ float与double的有效数字位 https://blog.csdn.net/VonSdite/article/details/76575247 

【5】使用STM32F4XX自带数学库"arm_math.h"  http://j1o1y.blog.sohu.com/275269554.html

【6】CMSIS库 http://www.keil.com/pack/doc/CMSIS/DSP/html/index.html

【7】http://www.keil.com/dd2/Pack/

发布了136 篇原创文章 · 获赞 112 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/heda3/article/details/100800923