将'浮动'转换为NSNumber,返回'浮动'的精度损失

时间:2011-10-29 01:26:02

标签: objective-c cocoa floating-point nsnumber

我似乎在Objective-C中遇到一个奇怪的问题,将浮点数转换为NSNumber(为方便起见将其包装),然后将其转换回浮点数。

简而言之,我的一个类有一个属性red,这是一个从0.01.0的浮动:

@property (nonatomic, assign) float red;

此对象将自身与从磁盘加载的值进行比较,以进行同步。 (该文件可以在应用程序外部进行更改,因此它会定期检查文件更改,将备用版本加载到内存中,并进行比较,合并差异。)

这是一个有趣的片段,其中比较了两个值:

if (localObject.red != remoteObject.red) {
    NSLog(@"Local red: %f Remote red: %f", localObject.red, remoteObject.red);
}

以下是我在日志中看到的内容:

2011-10-28 21:07:02.356 MyApp[12826:aa63] Local red: 0.205837 Remote red: 0.205837

怪异。对?这段代码是如何执行的?

存储在文件中的实际值:

...red="0.205837"...

使用:

转换为float
currentObject.red = [[attributeDict valueForKey:@"red"] floatValue];

在代码中的另一个点,我能够从GDB获取屏幕截图。它被打印到NSLog中:(这也是它在磁盘上文件中出现的精度。)

2011-10-28 21:21:19.894 MyApp[13214:1c03] Local red: 0.707199 Remote red: 0.707199

但在调试器中显示为:

GDB Screenshot

如何在属性级别获取此级别的精度,但不是存储在文件中,还是在NSLog中正确打印? 为什么它似乎变化了?

4 个答案:

答案 0 :(得分:5)

如果您在任何时候将其转换为字符串,请尝试使用%0.16f代替%f(或您想要的任何精度而不是.16)。

有关详细信息,请参阅IEEE Std formatting


此外,使用objectForKey代替valueForKeyvalueForKey不适用于词典):

currentObject.red = [[attributeDict objectForKey:@"red"] floatValue];

有关objectForKeyvalueForKey的更好解释,请参阅此SO答案:

Difference between objectForKey and valueForKey?

答案 1 :(得分:4)

您遇到的问题是浮点问题。浮点数并不完全代表存储的数字(除了一些在这里无关紧要的特定情况)。链接craig posted中的示例就是一个很好的例子。

在您的代码中,当您将值写入文件时,您会写出浮点数中存储的内容的近似值。当你加载它时,它的另一个近似值存储在浮点数中。然而,这两个数字不太可能相等。

最佳解决方案是使用两个浮点数的模糊比较。我不是一个客观的程序员,所以我不知道语言是否包含内置函数来进行这种比较。但是this link提供了一组很好的示例,说明了进行此比较的各种方法。

您还可以尝试使用更高精度的其他发布解决方案来写出您的文件,但您可能最终会浪费空间来获得您不需要的额外精度。我个人建议你使用模糊比较,因为它更具防弹性。

答案 2 :(得分:2)

您说“远程”值是“从磁盘加载”。我猜测磁盘上的表示不是IEEE浮点值,而是某种字符表示或某种类型。因此,考虑到IEEE float的工作方式,存在不可避免的转换错误。考虑到浮点值中只有大约6位十进制精度,你不会得到一个确切的结果,但它很少映射到正好6个十进制数字,而是有点像十进制的1/3 - 没有确切的映射。

答案 3 :(得分:0)

相关问题