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 的转换问题

NSDecimalNumber 比较失败

2016-5-25NSDecimalNumber 知识点的简单整理

如何在 Swift 中打印格式化的十进制值? [复制]

核心数据 - 货币的十进制类型

Swift 3 中的十进制到双精度转换