在Swift中将Double转换为NSNumber失去准确性

时间:2016-08-24 15:42:20

标签: ios swift double nsnumber

出于某种原因,我的Swift应用程序中的某些双打在转换为NSNumber时给我带来了麻烦,而有些则没有。我的应用程序需要将带有2位小数(价格)的双精度转换为NSNumbers,以便使用Core Data存储和检索它们。例如,除非使用NSNumber的doubleValue方法进行特殊格式化,否则一些特定的价格(例如79.99)将评估为99.98999999999999。

这里选择了Warranty.price = 79.99,如调试器中所示

// item.price: NSNumber?       
// selectedWarranty.price: Double?  

item.price = NSNumber(double: selectedWarranty.price!)

我编写了一些打印语句,以显示转换的工作原理

Original double: 79.99
Converted to NSNumber: 79.98999999999999
.doubleValue Representation: 79.99

有人可以解释一下,为什么初始化程序不能确保为每个数字保留2个小数位?我真的想将价格存储在核心数据中。每次显示时格式化都听起来不太方便。

更新: 将核心数据对象转换为通过数据模型输入NSDecimalNumber,79.99和99.99不再是问题,但现在使用不同的数字更易于管理...

Original double: 39.99
Converted to NSDecimalNumber: 39.99000000000001024

2 个答案:

答案 0 :(得分:10)

首先,您会混淆某些条款。 79.98999999999999的精度高于79.99(它具有更长的十进制扩展),但精度较低(它偏离真值)。

其次,NSNumber既不存储79.99也不存储79.98999999999999。它根据IEEE 754标准存储值的大小。您所看到的可能是印刷逻辑的结果,该印刷逻辑用于将该幅度转换为人类可读数字。在任何情况下,您都不应该依赖FloatDouble来存储具有固定精度的值。就其本质而言,他们牺牲精确度以获得更长范围的可表示值。

您最好将价格表示为Int美分或NSDecimalNumber

请参阅Why not use Double or Float to represent currency?

答案 1 :(得分:1)

到处都是双重的。如果你只需要2位小数,可以考虑使用整数/长而不是在第二位之后添加点,当需要显示值时。