2016-01-25 28 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不能完全由浮点数表示。 –