2016-08-24 167 views
8

出于某种原因,Swift应用程序中的某些双精度转换为NSNumber时会给我带来麻烦,而有些则不会。我的应用程序需要将2位小数(价格)的双打转换为NSNumbers,以便可以使用核心数据进行存储和检索。例如,除非使用NSNumber的doubleValue方法专门格式化,否则一些特定的价格(如79.99)将评估为99.98999999999999。在Swift中将Double转换为NSNumber失去准确性

这里selectedWarranty.price如图调试

// 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 

有人能解释一下,如果是有原因的79.99 =为什么初始值设定程序不能确保每个数字保留2位小数位?我真的很想将价格存储在核心数据中,就像他们应该那样。每次显示格式时听起来都不太方便。

UPDATE: 转换核心数据对象通过数据模型输入NSDecimalNumber,79.99和99.99不再是一个问题,但有不同的数字,现在更容易管理的问题...

Original double: 39.99 
Converted to NSDecimalNumber: 39.99000000000001024 
+1

你可以请一个[最小的,完整的和可验证的例子](http://stackoverflow.com/help/mcve)? – Alexander

+1

货币使用'NSDecimalNumber'而不是'NSNumber'。 – rmaddy

+0

我无法重现此问题。 http://swiftlang.ng.bluemix.net/#/repl/57bdc2590dcf4abf47da28c2 – Alexander

回答

9

首先,你”重新混淆了一些条款。 79.9899999999999979.99(它有一个更长的十进制扩展)更高的精度,但精度更低(它偏离真实值)。

其次,NSNumber既不存储79.99也不存储79.98999999999999。它根据IEEE 754标准存储值的大小。你所看到的可能是应用于将这个幅度转换为人类可读数字的打印逻辑的结果。无论如何,你不应该依靠FloatDouble来存储具有固定精度的值。就其性质而言,它们牺牲了精度以获得更大范围的可表示值。

如果将价格表示为Int分,或者作为NSDecimalNumber,则表示价格会更好。

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

+0

感谢您的解释。 NSDecimalNumber路线似乎最好。我唯一的问题是我如何让核心数据模型让我使用它而不是NSNumber?我在这方面不是很有经验 – joelrorseth

+0

我不知道,试着给它开个新的问题。如果你觉得这个答案满足你的直接问题,请将其标记为接受:) – Alexander

1

处处是如何双的作品。如果只需要2个小数位,则需要使用整数/长整数,而不是在第二个数字后面添加点,以便需要显示该值。