2016-08-24 168 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個小數位,則需要使用整數/長整數,而不是在第二個數字後面添加點,以便需要顯示該值。