我在我的应用程序中处理金额,因此精确度显然非常重要,十进制/ NSDecimal数字应该是快速处理金钱的方式。我想在保持精度的同时在Decimal和String之间进行转换。 (解析API响应,存储到DB ...)
这是我目前的解决方案:
private let dotLocaleDictionary = [NSLocale.Key.decimalSeparator: "."]
func apiStringToDecimal(_ string: String) -> Decimal? {
let number = NSDecimalNumber(string: string, locale: dotLocaleDictionary) as Decimal
return number.isNaN ? nil : number
}
func decimalToApiString(_ decimal: Decimal) -> String {
return (decimal as NSDecimalNumber).description(withLocale: dotLocaleDictionary)
}
语言环境字典负责小数分隔符,我希望字符串初始化程序是精确的。但是当我在操场上玩耍时,我注意到在一定长度的输入字符串后,结果数字会被切断。
我也尝试用数字格式化器解析字符串,但结果更糟。
我的游乐场代码:
let small = "1.135160000500009000100020003000400050061111"
let big = "1234567890123456789000100020003000400061111"
let medium = "123456789123456789.0001000200030004000511111"
let negative = "-123456789123456789.0001000200030004000511111"
let numericStrings = [small, big, medium, negative]
numericStrings.forEach {
print($0)
guard let decimal = apiStringToDecimal($0) else {
print("Failed to parse decimal from: \($0)")
print("--------------------")
return
}
print(decimal)
let string = decimalToApiString(decimal)
print($0 == string ? "match" : "mismatch")
print("--------------------")
}
let max = Decimal.greatestFiniteMagnitude
print("MAX decimal: \(max)")
print((max as NSDecimalNumber).description(withLocale: dotLocaleDictionary))
print(decimalToApiString(max))
它产生的输出:
1.135160000500009000100020003000400050061111
1.13516000050000900010002000300040005006
mismatch
--------------------
1234567890123456789000100020003000400061111
1234567890123456789000100020003000400060000
mismatch
--------------------
123456789123456789.0001000200030004000511111
123456789123456789.000100020003000400051
mismatch
--------------------
-123456789123456789.0001000200030004000511111
-123456789123456789.000100020003000400051
mismatch
--------------------
MAX decimal: 3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
从十进制转换为字符串似乎工作正常,字符串到十进制似乎是问题。由于我的数字小于最大十进制数,我认为我的测试数字不是很大。我很确定我已经排除了打印问题,并且我已经在实际设备上运行代码,所以这不是游乐场问题。
难道我做错了什么?在swift中有更好的方法在Decimal和String之间进行转换吗?
或者字符串太长了? (我还没有找到任何文件/讨论为什么这不起作用)
NSDecimalNumber是NSNumber的不可变子类,它提供了一个面向对象的包装器,用于执行base-10算术。实例可以表示可以表示为尾数x 10 ^指数的任何数字,其中尾数是长度为38位的十进制整数,指数是-128到127的整数。
(强调我的)
虽然NSDecimalNumber
提供精度很高的十进制算术,但精度有限。
您可能需要一个自定义库,例如BigNum。