快速回合问题

我有这个信息。

let params2: [String: AnyObject] = [ "app_token": myapptoken, "member_access_token": accessToken!, "pay_process": 0, "payamount_credit": 9.87 //hardcode ] 

当打印params2

结果是

["app_token": myapptoken, "member_access_token": accessToken, "payamount_credit": 9.869999999999999, "pay_process": 0]

"payamount_credit": 9.87现在是"payamount_credit": 9.869999999999999

我尝试了所有存在的方式,但performance相同。

NSString(format: "%.\2f", 9.87)

Double(round(1000*9.87)/1000)

最奇怪的是,只有这个具体数字(9.87)发生,是神秘的东西。

游乐场屏幕。

在这里输入图像说明

(浮动)这个原因,不要用浮动或双打代表货币。 改为使用NSDecimalNumber(请参阅哪种Swift数据types用于货币 )。

NSDecimalNumber需要一些努力来使用,但它确实执行了10进制算术。 要正确使用它,你必须在API上阅读一下。 特别是做四舍五入你需要提供一个NSDecimalNumberHandler(你可以设置一个默认值来使用)。

好的东西阅读:

认为游乐场显示出一个意想不到的结果,因为它显示之前强制NSDecimalNumber的内部值为Double(我会欢迎其他或权威的解释,因为我确实发现这个好奇)。 但是内部表示应该是正确的。

在你的游乐场试试这个:

 let myRoundingBehavior = NSDecimalNumberHandler(roundingMode: .RoundBankers, scale: 2, raiseOnExactness: true, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true) NSDecimalNumber.setDefaultBehavior(myRoundingBehavior) let integerPrice = NSDecimalNumber(mantissa: 987, exponent: -2, isNegative: false) integerPrice // 9.870000000000001 Float(integerPrice) // 9.87 Double(integerPrice) // 9.870000000000001 integerPrice.description // "9.87" 

不要以为浮点数是一个更准确的数字表示,它恰好在这里工作得更好。 如果你在NSDecimalNumber领域保持你的计算(如税收,折扣,运输等),它们将是准确的。


Swift 3 / Xcode beta 1奖金:

游乐场的行为仍然是一样的,但改变伟大的API重命名罗德奥更改上述代码为:

 let myRoundingBehavior = NSDecimalNumberHandler(roundingMode: .roundBankers, scale: 2, raiseOnExactness: true, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true) 

这里的改变是全局的NSRoundingMode枚举消失了,并且被NSDecimalNumber的成员枚举RoundingMode取代。

问题在于数字精确,简单地说,有些数字不能被定义为Double而不会失去精度。

相反,你应该使用NSDecimalNumber :

 let num = NSDecimalNumber(string: "9.87") 

尝试使用这个function:

 let price: Double = 9.87 func roundDouble(num: Double) -> Float { //Create NSDecimalNumberHandler to specify rounding behavior let numHandler = NSDecimalNumberHandler(roundingMode: NSRoundingMode.RoundDown, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false) let roundedNum = NSDecimalNumber(double: num).decimalNumberByRoundingAccordingToBehavior(numHandler) //Convert to float so you don't get the endless repeating decimal. return Float(roundedNum) } roundDouble(price) //9.87 

我认为在这里做的最好的事情是明确使用float而不是double,因为如果只需要两位小数,double的精度是不必要的。 这个function只是帮助它更准确一点。