2016-01-25 33 views
0

我想出了NSNumber的奇怪行爲。NSNumber與其floatValue不一樣

基本上是我的代碼API調用獲取JSON:

id json_response = [NSJSONSerialization 
          JSONObjectWithData:data 
          options:NSJSONReadingMutableLeaves 
          error:&error]; 

,並存儲爲NSDictionary

然後我從中得到了NSNumber和使用NSNumberFormatter將其轉換爲一個字符串,但...

NSNumber * avgNumber = [[_tableDataArray objectAtIndex:index ] 
          objectForKey:kTrendsKeyAvgScoreFloat]; 

這裏是格式化輸出:

NSNumberFormatter * formatter = [[NSNumberFormatter alloc]init]; 
[formatter setDecimalSeparator:@","]; 
[formatter setMaximumFractionDigits:1]; 
[formatter setMinimumFractionDigits:0]; 
[formatter setGroupingSeparator:@"."]; 
[formatter setGroupingSize:3]; 
[formatter setNumberStyle:NSNumberFormatterDecimalStyle]; 
NSString * retString = [formatter stringFromNumber:number]; 

我奇怪的行爲時NSNumber有1.05

(__NSCFNumber *) avgNumber = 0x0000000155923800 (float)1.050000 

值,但與上面代碼中它被打印(而不是預期的1.1):

1 

然而,當我檢查浮點值

float avg = [avgNumber floatValue]; 

原來,

Printing description of avg: 
(double) avg = 1.0499999523162842 

即使我嘗試將其四捨五入到小數點後2分

avg = roundf(avg * 100); // here 105 
    avg = avg/100; // and here is 1.0499999523162842 again 

但是如果我對代碼進行測試並手動將1.05內NSDictionary一切正常。

如果有人能解釋這是爲什麼?如何保持每次正確的顯示?

+0

不清楚你的問題是什麼。是不是'NSNumberFormatter'生成'1'而不是'1.1'?在這種情況下,這是因爲它縮小了。或者你被數字「1.04999」而不是「1.05」所困惑?在這種情況下,這只是一個浮點舍入錯誤。 – trojanfoe

+1

http://floating-point-gui.de –

+0

是的,我很困惑,因爲我有1.05,它應該四捨五入到1.1而不是1. – mazziek

回答

4

問題是1.05的值不能完全由浮點數表示。這僅對於(正或負)2的冪和的值纔是可能的。因此,可以精確地表示像1(= 2^0)或1.03125(= 2^0 + 2^-5)的值,但是1.5的最佳近似值在你的情況1.0499999523162842。
現在,當你初始化一個NSNumberFormatter,並且未設置其roundingMode屬性,它的默認值是kCFNumberFormatterRoundHalfEven,這意味着數字將四捨五入「向最近的整數,或者對是否等距偶數。」
所以,如果你數字是1.0499999523162842,它將舍入到1.0,並且輸出爲1.

+0

這對我來說非常清楚,謝謝。那麼如何向終端用戶顯示正確的號碼?因爲即使使用正確的舍入模式也無濟於事,因爲它會舍入1.0499999523162842而不是1.05 – mazziek

+0

如果您不想舍入整數,而是舍入一半的整數(在您的情況下爲1,05),您可以這樣做: 如果x是要四捨五入的值,將整數2舍入爲2,並將結果除以2 1,0499 * 2 = 2,0998,四捨五入= 2,1/2 = 1,05。但是,如前所述,1,05不能完全由浮點數表示。 –