前幾天,有個小伙伴在做實驗過程中,發現了一個奇怪的現象,這個現象就是…
他在用printf輸出浮點數的時候,想把數據保留到小數點后的兩位,他是這么寫的…
float c=1.155;printf(“%.2f”,c);
他的書寫是對的,沒有錯誤。但是他發現,當c等于1.555時,保留兩位小數輸出是1.55,而當c等于3.555時,保留兩位小數輸出是3.56。這個結果,就讓人捉摸不透了,因為…
如果是程序運算會自動四舍五入的話,結果應該是1.56和3.56;如果程序運算不會自動四舍五入的話,結果應該是1.55和3.55??墒墙Y果卻是1.55和3.56,這是什么鬼?
如果你去百度輸入關鍵詞“浮點數 四舍五入”,你會發現,有些人會說浮點數會自動四舍五入,如下圖…
而有些人會說,不會自動四舍五入,如下圖…
到底會不會自動四舍五入呢?
我剛才拿老頑童STM32開發板做了一個實驗,我定義了6個浮點數,他們分別是…
然后我用printf給他們保留2位小數后輸出,程序如下…
在串口調試助手上看到的結果是…
結果是,6個數,有3個數自動四舍五入了,有3個數沒有四舍五入。
不管理論是什么,我們只看結果。結果是:浮點數保留小數點后的數據,有時會自動四舍五入,有時不會自動四舍五入。但是…
如果把一個浮點數賦給一個整數變量后,一定不會四舍五入。
所以,我們在保留浮點數的小數點精度時,必須要人工處理四舍五入。
很多人一直在用的一個的方法,就是加0.5法。
這個方法的理論依據是:
float f;//定義了一個浮點數
int t;//定義了一個整數
我們執行(t=f;)這條語句,不管f的小數點后面是小于5的數,還是大于等于5的數,都不會四舍五入,例如當f=3.2和f=3.8,結果都是t=3。
那么怎么樣讓f=3.8時,t=4呢?我們可以給f+0.5來解決,例如當f=3.8時,f+0.5=4.3,執行完t=f后,t就等于4了。而當f的小數點后的的數都小于5時,加一個0.5不會大于4,所以執行完t=f后,結果還都是3。這正好符合我們四舍五入的要求。
這里需要注意的是:其實這個…
加0.5的方法
只適合用于保留整數位的應用
很多人都不知道這一點,下面我就給大家實踐一下。
按照加0.5法的原理,如果要保留2位有效數據的話,需要給數據加0.005,我們做個實驗,把temp1~6都加0.005。
然后我們看輸出結果,如下圖…
看到了正確的結果,你不要高興,因為…
你現在可以把temp1~6的小數點后面都改為554,如下圖…
這時候,正確的結果,小數點后兩位應該都是55,但是你看看結果,還是照樣是56。這時候,就輸出了完全錯誤的結果。
有的朋友會說,既然加0.005不行,那我們想辦法還是加0.5吧。好的,下面我有一個方法…
先把temp1*100,然后再+0.5,然后把這個浮點數賦值給一個整數,然后再把這個整數除以100。
例如temp5的程序寫為…
temp5=temp5*100+0.5;
t5=temp5;
temp5=(float)t5/100;
其中,t5是我定義的一個uint32_t類型的整型變量。我們來分析一下,因為temp5=4.555,4.555乘以100以后是455.50,然后再加0.5以后是456.00,把456.00取整后是456,然后456除以100就是4.56。
一切都算計的很好,但是實際的結果卻還是4.55。但是如果你這樣寫的話,結果就是正確的…
temp5=4.555*100+0.5;
t5=temp5;
temp5=(float)t5/100;
看這個程序和上邊的程序對比一下,只是這里直接用了4.555,而上邊的程序用了temp5,看似一樣,結果卻不一樣。上邊程序的結果是4.55,下邊程序的結果是4.56。
上邊兩個加0.5的實踐,你一定要試一下。
那保留2位小數,怎么做才能確保完全正確?
送給大家一句話:捷徑有可能是歧途,最笨的辦法,其實是最保險的辦法。(頑童哥語錄一定要收藏)
我們可以把小數點后的第三位數取出來,然后判斷它和5的大小,然后四舍五入。就是這個方法,絕對正確。寫成程序的話,是這個樣子的…
其中,t1是定義的uint32_t類型的整型變量。我們把數據帶進去看一下,temp1是0.555,0.555乘以1000是555,555除以100取余數是55,55再除以10取余數是5,那t1就等于5。下面用if語句判斷是否要進位,如果需要進位的話,4.555乘以100就是455.5,455.5加1就是456.5,然后我們把456.5強制類型轉換成整型數據,就是456,456除以100,就是4.56;如果不需要進位的情況,大家自行分析。
這時候,你去換temp1~6的值去吧,不管換什么,結果都會四舍五入。
做一個穩定的電子產品,基礎知識很重要!