NSDecimalNumber 问题
Posted
技术标签:
【中文标题】NSDecimalNumber 问题【英文标题】:NSDecimalNumber issues 【发布时间】:2015-02-17 19:33:16 【问题描述】:在我的 ios swift 应用程序中,我从网络收到一些 json,其中包含一些代表货币的双精度值。它看起来像这样:
["Amount": 5.0,"Amount":-26.07,"Amount": 4, ...etc]
我将它们转换为 Double,然后尝试将这些值作为 Swift“Double”输入到 NSDecimalNumber 的构造函数中,如下所示:
let amount = NSDecimalNumber(double: amountAsDouble)
我在使用这种方法时遇到了问题,因为我创建的 NSDecimalNumber 经常会包含一个不同的数字,该数字经过小数点后 16 位。
let amount = NSDecimalNumber(double: -15.97)
println(amount)
这将返回 -15.970000000000004096
我不想要这个,我想要 -15.97。 谢谢,
【问题讨论】:
【参考方案1】:我最近亲身经历了这个。我最终使用 NSNumberFormatter 来获得正确的小数位。
let currFormatter = NSNumberFormatter()
currFormatter.numberStyle = .DecimalStyle
currFormatter.roundingIncrement = 0.01
currFormatter.minimumFractionDigits = 2
currFormatter.maximumFractionDigits = 2
let doubleAmount = currFormatter.numberFromString(amountAsDouble) as NSNumber!
let amount = doubleAmount as Double
println(amount)
【讨论】:
【参考方案2】:这里有个提示:如果你使用 NSJSONSerializer,带小数点的数字实际上会为你转换成 NSDecimalNumber。 NSDecimalNumber 是 NSNumber 的子类。所以你在做什么:你有一个非常好的 NSDecimalNumber,将值四舍五入到 double,然后尝试将 double 转回 NSDecimalNumber。只需检查您所拥有的确实是一个 NSDecimalNumber,如果是,则不要进行转换。
【讨论】:
这是一个有用但有点误导的答案。 (NS)JSONSerialization 将数字转换为 NSNumber,而不是 NSDecimalNumber。您可以使用 NSNumber 的 decimalValue 属性来获取 (NS)Decimal。【参考方案3】:Double
存储有 18 位十进制数字,您对此无能为力,它就是这样工作的。
在这里阅读:http://en.wikipedia.org/wiki/Double-precision_floating-point_format
但是,在屏幕上显示值时,您可以像这样使用NSNumberFormatter
:
let amountInDouble: Double = -15.970000000000004096
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
formatter.roundingIncrement = 0.01
formatter.maximumFractionDigits = 2
let amountAsString = formatter.stringFromNumber(NSNumber(double: amountInDouble))
if let amountAsString = amountAsString
println(amountAsString) // -15.97
【讨论】:
【参考方案4】:这是因为中间双精度表示会导致问题。
您应该将字典中的值作为NSString
对象并使用+ decimalNumberWithString:
方法进行转换而不会丢失精度。迅速:
let amount = NSDecimalNumber(string: amountAsString)
【讨论】:
我会试试这个,然后回来标记为答案或提出另一个问题。谢谢 好的,所以我在将 json 的值转换为字符串时遇到了一些麻烦。我试图做的实际上只是保持之前的 Double 值并改用它。到目前为止一切顺利,但我担心在某些情况下,Double 值会失去它的精度。 这似乎不起作用 - 它仍然会导致精度损失。 NSDecimalNumber(string: "9277.235") -> 返回 9277.2350000000001【参考方案5】: let amount = NSDecimalNumber.init(value: -15.97)
let roundValue = amount.rounding(accordingToBehavior: NSDecimalNumberHandler(roundingMode: .bankers, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false))
print(roundValue)
【讨论】:
以上是关于NSDecimalNumber 问题的主要内容,如果未能解决你的问题,请参考以下文章
NSDecimalNumber 到 UInt64 的转换问题