2013-03-31 87 views
3

我試圖將浮點數顯示爲小數點後一位。我得到意想不到的結果如下:使用%.1f時打印的意外值

代碼:

float a = 1.25; 
float b = 1.35; 

NSLog(@"1.25 -> %.1f\n1.35 -> %.1f",a,b); 

輸出:

1.25 - > 1.2

1.35 - > 1.4

預期輸出,要麼:

1.25 - > 1.3

1.35 - > 1.4

或:

1.25 - > 1.2

1.35 - > 1.3

這是隻是由於b之間的內部轉換inary和小數?如果是這樣,我如何得到預期的行爲?

我正在使用Xcode 4.6。

編輯:好的,感謝TonyK和H2CO3,這是由於小數的二進制表示。

float a = 1.25; 
float b = 1.35; 
NSLog(@"1.25 -> %.30f\n1.35 -> %.30f",a,b); 

1.25 - > 1.250000000000000000000000000000

1.35 - > 1.350000000000000088817841970013

很多好消息,但據我所見,沒有人走近第二個問題:我如何得到預期的行爲?

Rounding numbers in Objective-C是一個完全不同的問題。

+1

這涉及到所有的C語言,而不僅僅是目標C.你得到什麼取決於系統,1.25可以打印爲1.2或1.3。 – teppic

回答

2

這是因爲浮點數不準確。 %.1f打印數字四捨五入到一位小數,但它似乎,1.35不能準確地表示爲1.2500000,而是它可以是一個稍小的數字。

閱讀關於此行爲的信息:What every computer scientist should know about floating-point numbers

+3

1.25 = 5/4可以精確表示,因爲4是2的冪。它是1.35 = 27/20,不能精確表示。 – TonyK

+1

@TonyK對,但爲什麼它被截斷而不是四捨五入? – 2013-03-31 10:04:50

+0

好的,謝謝TonyK和H2CO3。您可能對我的編輯感興趣,它顯示%.30f的行爲作爲演示。爲了獲得一致的行爲,解決這個問題的常用方法是什麼? – putridp

5

1.35是27/20,這在二進制是

1.01 0110 0110 0110 0110 0110 0110.... 

float對大多數系統一個23位的尾數(不算隱含的前導1),所以這獲取向上舍入到

1.01 0110 0110 0110 0110 0110 1 

(因爲0110明確地大於1000的一半)。所以在printf看到它時它嚴格大於1.35。因此1.4。

至於1.25,這是二進制精確表示作爲

1.01 

所以printf看到它的精確值。但是,它應該如何在1.25?我們在學校教過5到10。但是大多數現代系統在硬件級別使用默認舍入模式「舍入到偶數」,因爲它減少了累積舍入誤差的影響。這意味着,當一個數字恰好在兩個最接近的候選人之間進行四捨五入時,它會被四捨五入到偶數候選人。

所以看來print正在使用「round to even」作爲十進制輸出!我在this ideone link檢查了這個假設,事實上1.75被取整爲1.8。這對我來說是一個驚喜,但不是一個巨大的。

+0

感謝您爲挖掘整個二進制表示做出的努力。 +1。 – 2013-03-31 11:02:30