tft每日頭條

 > 科技

 > 嵌入式浮點計算測試程序

嵌入式浮點計算測試程序

科技 更新时间:2024-06-27 00:58:18

嵌入式浮點計算測試程序?1 背景一款流量計量産品,涉及到浮點數的累加,由于當時對浮點數的格式沒有深入了解,想當然的就直接累加了程序編制完畢,在調試時發現下列問題:瞬時量測量精度高于指标要求,累積量在程序運行的開始階段精度也滿足要求,但随着測量時間的增長,累積量的實際測量值和理論計算值之間的差别越來越大,超過了技術指标的要求若不加幹涉任其運行,當時間足夠長時,顯示模塊顯示的數據不再發生變化,即流量計的累積量不再發生變化了,但此時瞬時量顯示的數據依舊正确,下面我們就來聊聊關于嵌入式浮點計算測試程序?接下來我們就一起去了解一下吧!

嵌入式浮點計算測試程序(嵌入式系統中浮點數累加問題)1

嵌入式浮點計算測試程序

1 背景

一款流量計量産品,涉及到浮點數的累加,由于當時對浮點數的格式沒有深入了解,想當然的就直接累加了。程序編制完畢,在調試時發現下列問題:瞬時量測量精度高于指标要求,累積量在程序運行的開始階段精度也滿足要求,但随着測量時間的增長,累積量的實際測量值和理論計算值之間的差别越來越大,超過了技術指标的要求。若不加幹涉任其運行,當時間足夠長時,顯示模塊顯示的數據不再發生變化,即流量計的累積量不再發生變化了,但此時瞬時量顯示的數據依舊正确。

表1 累積量測試結果

序号

累加初值

累加終值

實際累加值

誤差

1

321

920

599

-0.17%

2

932

1524

592

-1.33%

3

1633

2223

590

-1.67%

4

2956

3537

581

-3.17%

某次測試時,通過設置流量計參數,使瞬時量理論值3600t/h,以10min為一個測量周期進行測量,理論計算得累積量每個周期應累加600。實測數據如表1所列。由表1中的數據可知,第1個測試周期精度滿足要求,從第2個周期開始誤差已經超過了技術指标要求,并且誤差随着時間的增加而增大,在這種狀态下流量積算儀是無法正常工作的。為什麼會出現這種累加誤差呢?要解決這個問題我們就有必要先了解一下浮點數的定義及在内存中存儲格式。

2 浮點數的存儲格式

實數r的二進制科學計數法可表示為r=(- 1)S×2E× M, 其中 S ( Sign)為實數的符号, “0”正 “1”負。E ( Exponent ) 為二進制數的指數, M( Mantissa)表示尾數,規範的二進制數 M = 1. d1d2 …dN C 語言的浮點數類型Float和Double采納了IEEE 754标準中所定義的單精度32位浮點數和雙精度64位浮點數的格式。具體的格式參見表 2和表3。

表中的指數域采用移碼方式存儲,單精度要指數值加上偏移量127,雙精度要指數值加上偏移量1023。比如,單精度的實際指數值0在指數域中将保存為127;而保存在指數域中的64則表示實際的指數值-63。對于單精度數,可以表達的指數值的範圍在-127~ 128 之間(包含兩端) 。實際的指數值-127(保存為全0)以及 128(保存為全1)保留用作特殊值的處理。這樣,實際可以表達的有效指數範圍就在-126~ 127之間。

表中的第三個域為尾數域,其中單精度數為23位長,雙精度數為52位長。除了某些特殊值外,IEEE 标準要求浮點數必須是規範的。這意味着尾數的小數點左側必須為1,因此在保存尾數的時候,可以省略小數點前面這個1,從而騰出一個二進制位來保存更多的尾數。這樣實際上用23位長的尾數域表達了24位的尾數。

表2 單精度浮點數

符号

指數

尾數

1bit

8bit

23bit

表3 雙精度浮點數

符号

指數

尾數

1bit

11bit

52bit

值得注意的是,對于單精度數,由于我們隻有24位的尾數(其中一位隐藏) ,所以可以表達的最大尾數為224-1= 16777215。由此,我們可以看到單精度的浮點數可以表達的十進制數值中,真正有效的數字不高于8 位。 Float型的一些特殊約定:

1) 當E= 0,M= 0時,表示0;

2) 當E = 0,M!= 0時,表示非規範化數,即r= (-1) S×2-127×( 0. M) ;

3) 當E = 255,M= 0時,表示無窮大,用符号位來确定是正無窮大還是負無窮大;

4) 當E= 255, M! = 0時,表示 N aN (No t a Number,不是一個數);

對于Double型,也有相似的約定。

3 浮點數累加誤差問題解決

通過對累積量測試結果的分析我們找到了産生誤差的原因:程序中在計算累積量SUM時執行的是SUN=SUM Instant,而參考文獻明确告訴我們,兩個浮點數相加時,其誤差随着兩個數差别的增大而增大。表1中誤差的變化規律也證明了這一點。這是因為每次執行語句“SUM=SUM Instant;”時,Instant是不變的,而SUM在不斷增加。當兩者大小相差的數量級足夠大時,Instant與SUM相加會丢失Instant,緻使流量計累積量讀數不再發生變化,這也是前面調試時出現問題的原因。

為什麼兩個相差很大的浮點數相加會誤差很大呢?通過上面對浮點數存儲格式的分析可以知道,由于Float 型變量是用有限的存儲單元存儲的,因此能提供的有效數字總是有限的,在有效位以外的數字将被舍去,由此可能會産生一些誤差。

例如:

Main( )

{ float a, b;

a=123456.789e5;

b=a 20.0f;

printf(“a=%f\n b=%f\n”,a ,b) ; }

運行結果:

a=12345678848.000000

b=12345678848.000000

輸出結果是a與b相等。但理論上b應比a大20,應為12345678920。而Float型變量隻能保證7位有效數字。後面的數字是無意義的,并不準确地表示該數。因此應該避免将一個很大的數和一個很小的數直接相加或相減,否則就會“丢失”小的數。

知道了以上原因,對于累積量的累加我們就有了應對措施。在程序中将累積量的變量分為整數部分和小數部分分别定義,即定義兩個float型變量INT_SUM和FP_SUM。INT_SUM中隻保存累積量的整數部分,而FP_SUM中保存累積量的小數部分。在進行流量的累積計算時執行“FP_SUM=FP_SUM Instant;”當FP_SUM中的值大于等1.0時,INT_SUM=INT_SUM 1,同時FP_SUM=FP_SUM-1.0,這樣FP_SUM中的值就始終是小于1的小數。因為INT_SUM=INT_SUM 1始終執行的是整數操作,不存在精度問題,而執行“FP_SUM=FP_SUM Instant;”時FP_SUM是小于1的小數部分,Instan每秒也是小于等于1(最大量程是3600t/h)的數據,二者相加精度也是滿足要求的。最終的累積量等于INT_SUM 與FP_SUM的和,顯示時先求二者的和再進行顯示。雖然在求INT_SUM 與FP_SUM的和時也存在誤差,但誤差不是累積的,不會随時間的推移而增大,并且FP_SUM隻是小于1的小數部分,最終誤差可以忽略不計。

采用上述方法對累積量進行處理後,很好地解決了測量精度随時間增加而變大的問題,最終使計量精度達到了供需雙方都滿意的範圍。

4 C語言中浮點數使用時的幾點建議

通過以上對C語言中浮點數存儲格式的及實際應用中的問題分析,可以得出一下結論:

(1)避免将一個很大的浮點數和一個很小的浮點數數直接相加或相減

因為這樣做可能會丢失小的數。特别是在累加計算時,由于初始時,基數很小可能看不出問題,但随着時間的推移,基數的增大,問題就出來了。這給程序的正常運行埋下了隐患。

(2)避免對兩個浮點數直接做是否相等的判斷

由于浮點數在内存中的存儲誤差,因此可能出現這樣的情況:在理論上應該相等的兩個數,用計算機卻判斷它們卻為不相等。如果想判斷x是否等于y ,應改寫為:fabs(x-y)<10-6,或小于一個其它足夠小的數。隻要小于此數,就認為x和y 足夠地接近,近似地認為相等。如果x和y的值比較大(如約等于1030) ,則x-y的差可能大于 10-5,因此可用相對誤差,即fabs((x-y)/x)<10-5,當此關系表達式的值為真時,x和y的相對誤差小于百萬分之一。

(3)慎用浮點數作為循環變量

C語言中的循環變量可以用浮點數,但是使用浮點數作為循環變量一定要仔細考慮,由于浮點數的誤差,可能會使循環次數達不到預定的次數而導緻程序出現邏輯錯誤。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved