在使用 Decimal 型別處理貨幣輸入時,我遇到了精度問題。問題在于格式化程式。這是 Playground 中最小的可重現代碼:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.isLenient = true
formatter.maximumFractionDigits = 2
formatter.generatesDecimalNumbers = true
let text = "89806.9"
let decimal = formatter.number(from: text)?.decimalValue ?? .zero
let string = "\(decimal)"
print(string)
它列印出來89806.89999999999而不是89806.9. 但是,大多數其他數字都很好(例如8980.9)。所以我不認為這是一個 Double vs Decimal 問題。
編輯:
我需要使用格式化程式的原因是有時我需要處理貨幣格式輸入:
let text = "$89,806.9"
let decimal = formatter.number(from: text)?.decimalValue ?? .zero
print("\(decimal)") // prints 89806.89999999999
let text2 = "$89,806.9"
let decimal2 = Decimal(string: text2)
print("\(decimal2)") // prints nil
uj5u.com熱心網友回復:
使用新的 FormatStyle 似乎會產生正確的結果
let format = Decimal.FormatStyle
.number
.precision(.fractionLength(0...2))
let text = "89806.9"
let value = try! format.parseStrategy.parse(text)
下面是使用語言環境中的貨幣代碼決議貨幣的示例
let currencyFormat = Decimal.FormatStyle.Currency
.currency(code: Locale.current.currencyCode!)
.precision(.fractionLength(0...2))
let amount = try! currencyFormat.parseStrategy.parse(text)
瑞典語示例:
let text = "89806,9 kr"
print(amount)
89806.9
uj5u.com熱心網友回復:
我同意這是一個令人驚訝的錯誤,我會打開一個 Apple 反饋關于它,但我也強烈建議切換到Decimal(string:locale:)而不是格式化程式,這將實作您的目標(可能除了isLenient部分之外)。
let x = Decimal(string: text)!
print("\(x)") // 89806.9
如果你想修正小數位數,你可以* 100 / 100通過 Int 轉換很容易地應用舍入。(如果不明顯,我將解釋如何執行此操作;它適用于 Decimal,但不適用于 Double。)
uj5u.com熱心網友回復:
如果這嚴格來說是一個渲染問題,并且您只是想將貨幣值從原始字串轉換為格式化字串,那么就這樣做。
let formatter = NumberFormatter()
formatter.numberStyle = .currency
let raw = "89806.9"
if let double = Double(raw),
let currency = formatter.string(from: NSNumber(value: double)) {
print(currency) // $89,806.90
}
如果涉及數學,那么在您開始使用字串格式化程式之前,我會指出您 為什么不使用 Double 或 Float 來表示貨幣?以及 如何使用 C 語言中的銀行家舍入作為很好的起點,將雙精度數舍入為 int。
uj5u.com熱心網友回復:
我得到雙值的回應并洗掉 formatter.generatesDecimalNumbers 行以開始作業。
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.isLenient = true
formatter.maximumFractionDigits = 2
//formatter.generatesDecimalNumbers = true // I removed this line
let text = "$89806.9"
let double = formatter.number(from: text)?.doubleValue ?? .zero // converting as double or float
let string = "\(double)"
print(string) // 89806.9
let anotherText = "$0.1"
let anotherDouble = formatter.number(from: anotherText)?.doubleValue ?? .zero // converting as double or float
let anotherString = "\(anotherDouble)"
print(anotherString) // 0.1
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/431348.html
標籤:迅速
