前幾天,有個小夥伴在作實驗過程當中,發現了一個奇怪的現象,這個現象就是…ui
他在用printf輸出浮點數的時候,想把數據保留到小數點後的兩位,他是這麼寫的…spa
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。但是結果倒是1.55和3.56,這是什麼鬼?產品
若是你去百度輸入關鍵詞「浮點數 四捨五入」,你會發現,有些人會說浮點數會自動四捨五入,以下圖…io
而有些人會說,不會自動四捨五入,以下圖…class
到底會不會自動四捨五入呢?基礎
我剛纔拿老頑童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的值去吧,無論換什麼,結果都會四捨五入。
作一個穩定的電子產品,基礎知識很重要!