天天看點

嵌入式代碼優化(C語言)

優化方法:

1、二維數組相比一維數組存儲

2、整數運算相比浮點運算

3、乘除法和移位運算

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

4、查表運算

比如計算cos sin 函數

例如:

嵌入式代碼優化(C語言)

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/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

嵌入式代碼優化(C語言)

下載下傳該庫的方法:到keil官網下載下傳keil5安裝包,完成後有庫所在的檔案路徑如下所示:

嵌入式代碼優化(C語言)

參考資料:

【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/

繼續閱讀