根據經驗,我盡量避免在嵌入式系統代碼庫中使用浮點數。
浮點變量是:
- 計算密集型
- 不是原子性的(可能會在RTOS應用程序或中斷中引起問題)
- 它們的精度可能導致不明顯的行為(浮動比較問題)。
但是帶有浮點單元(如STM32F4)的微控制器又如何呢?
那些擔憂仍然適用嗎?您仍然建議不要使用浮點數嗎?
根據經驗,我盡量避免在嵌入式系統代碼庫中使用浮點數。
浮點變量是:
但是帶有浮點單元(如STM32F4)的微控制器又如何呢?
那些擔憂仍然適用嗎?您仍然建議不要使用浮點數嗎?
您應該記住,這些微控制器上的FPU通常只是單精度FPU。單精度浮點只有24位尾數(帶有隱藏的MSB),因此在某些情況下,您可能會從32位整數獲得更好的精度。
我已經完成了使用定點算法的工作,並且在數據的動態範圍有限的情況下,您可以使用32位定點實現與單精度浮點相同的精度,並提高大約一個數量級。在執行時間。我還看到編譯器為FPU拖了相當多的庫開銷。
如果您購買的是帶有硬件FPU的處理器,那麼您就不會對精度*,可重入行為等產生同樣的擔憂。請繼續使用它們!
雖然有思想:
您可能會認為處理器在不使用時可以關閉(大型)FPU,因此請檢查運行FP例程是否可以節省(如果您在意)軟件方面的功能。
取決於實現方式,FPU的內核可能還具有不同的寄存器-有時編譯器可以巧妙地使用它們。
不要將FPU用作劣質固件設計的拐杖。例如,您可以在定點上做同樣的事情,而改用普通核心嗎?
(* FPU應該符合給定的標準實現,因此請注意由此產生的任何限制。)
某些擔憂仍然存在。
尤其是後一種可能會引起非常討厭的問題,並迫使您編寫非直觀的代碼,例如始終與範圍進行比較,從不針對固定值測試相等性。
請記住,單精度浮點數只有23位分辨率,因此您可能需要用雙精度浮點數替換32位整數。
如果您有FPU,通常可以進行計算,而且權衡很容易理解。
但是請注意輸出。如果您擁有C庫之類的東西,您會驚訝於 printf(“%0.6g”,x);固有的複雜性;
我見過使用 malloc的庫()
放在 printf()
中,而這並不是您在微控制器中想要的。
老實說,這是一種微優化,您應該在擁有完全正常工作的代碼庫之後 進行。一些MCU也存在除法問題,即使是整數也是如此。因此,執行“將fp乘以100,進行一些操作,然後除以100”之類的操作可能要比僅操縱浮點型花費更多的時間。
這是剖析出現的地方,您需要選擇自己的戰鬥,沒有答案。有了可用的代碼庫後,您可以確定瓶頸並有選擇地進行優化。避免使用籠統的聲明會導致微優化,這比實際節省了更多的時間來編寫代碼。從每小時運行一次的低優先級例程中優化出浮點數是沒有用的,而針對繁重的任務優化出浮點數很有用。
基本上沒有必要避免使用FPU,並且RTOS也支持FPU的上下文切換。如果沒有FPU,精度問題仍然存在。如果您有性能的話,也可以自由使用不帶FPU的浮點數-偶爾在不帶FPU的Cortex-M3上調試float變量就可以了。但是很顯然,在內存較小的有限8位MCU上,即使使用單個float操作也會帶來數百字節的軟float庫代碼的開銷,因此有時使用float沒有意義。
何時不使用浮點數
第一個需要意識到的是 不是 的浮點表示“我需要小數”。在這裡,有95%的潛在嵌入式程序員濫用浮點運算會失敗。
解決該懷疑的方法是在內部認識到,程序應該使用對 MCU 有意義的單元,而不是對人類有意義的單元。
例如,如果使用片上10位ADC以mA為單位測量電流,則在軟件中使用的方便單位是“定點原始ADC值從0到1024”。在C編程中,這意味著 uint16_t
或可選的 uint_fast16_t
。不是 int
,當然也不是 float
。
在固件計算中使用單位mA僅在無法處理抽象單位的情況下,對於人類程序員的大腦來說非常方便。但這對程序來說很不方便,因為這意味著您需要將所有讀數重新調整為比例,並可能在這樣做時增加舍入誤差。再加上縮放代碼只是開銷腫。而且可能包括除法,這對於許多MCU來說可能是痛苦的。
是的,您正在讀取以mA為單位的電流。但是,除非您實際上需要在顯示器上打印該電流或將其打印給人類用戶,否則該設備實際上無濟於事。在設計算法時,請在筆和紙上進行mA重新縮放,而不是將其拖到固件中。
何時使用浮點
“高級數學”並不一定意味著從程序員的角度出發,而是從軟件的角度來看。“高級”包括諸如平方根,幾何或三角學,通常使用 math.h
,複數,AI數學等。在定點實現時會很痛苦。
我將從原因列表中排除非原子操作,因為您處理其他復雜結構的方法也可以應用於浮點操作。
我還將從原因列表中排除所需的計算能力,因為這是高度針對應用程序和處理器的。
讓我們關注由浮動精度變化引起的“非顯而易見”問題
最基本的一個是FP算法是非關聯的,(a + b)+ c不等於a +(b + c)。假設a = 1,b = -1,c = 1e-20。聽起來無害,但假設您的應用程序使用了有限脈衝濾波器,並運行了一個假設為零的測試用例
的第二個原因是整數和固定逗號運算在我期望的範圍內發生溢出(好的,默認情況下未在C中啟用)。例如在浮點中,積分器可以輕易地跑到非常大的值,而無需任何人注意...
就像很多事情一樣,這取決於您的用例。
如果您知道輸入值的允許範圍,則定制整數算法可能會更有效率(例如,乘以)。隨著這些值的擴大,無論您編寫什麼代碼,都將退化為浮點乘法,而沒有硬件的好處。
通過在後台循環中運行嵌入式系統或確定具有不同處理器的慢速計算可能難以確定嵌入式系統的時序。控制和計算。