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

Converting Double to NSNumber in Swift Loses Accuracy

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

此处selectedWarranty.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 位小数吗?我真的很想像应该的那样将价格存储在核心数据中。每次显示都要格式化,听起来不是很方便。

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

Original double: 39.99
Converted to NSDecimalNumber: 39.99000000000001024

首先,您混淆了一些术语。 79.9899999999999979.99精度高(小数点展开时间更长),但准确率低(偏离真实值)。

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

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

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

这就是 double 在任何地方的工作原理。如果您只需要 2 位小数,请考虑使用 integer/long 而不是在需要显示值时在第二位数字后加点。