我有这个信息。
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
我已经尝试了所有存在的方法但行为相同。
NSString(format: "%.\2f", 9.87)
Double(round(1000*9.87)/1000)
最奇怪的是,只有这个特定的数字(9.87)发生,才是神秘的。
游乐场屏幕。
答案 0 :(得分:4)
不要使用浮点数或双打来代表货币,这是因为(双关语)这个原因。请改用NSDecimalNumber(参见Which Swift datatype do I use for currency)。
NSDecimalNumber需要花费一些精力才能使用,但它确实执行了基数为10的算术运算。要正确使用它,您必须阅读API。特别是,要进行舍入,您需要提供NSDecimalNumberHandler(您可以设置要使用的默认值)。
阅读的好东西:
我认为 Playground显示意外的结果,因为它在显示之前将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"
不要认为Float是一个更准确的数字表示,它恰好在这里工作得更好。如果您在NSDecimalNumber领域保留计算(如税,折扣,运费等),它们将是准确的。
Swift 3 / Xcode beta 1奖金:
Playground行为仍然相同,但更改Great API Renaming Rodeo会将上述代码更改为:
let myRoundingBehavior = NSDecimalNumberHandler(roundingMode: .roundBankers,
scale: 2,
raiseOnExactness: true,
raiseOnOverflow: true,
raiseOnUnderflow: true,
raiseOnDivideByZero: true)
这里的变化是全局NSRoundingMode枚举消失了,并被枚举RoundingMode取代,它是NSDecimalNumber的成员。
答案 1 :(得分:3)
问题在于numeric precission,简单地说,有些数字不能定义为Double
而不会失去精确度。
相反,您应该使用NSDecimalNumber:
let num = NSDecimalNumber(string: "9.87")
答案 2 :(得分:1)
尝试使用此功能:
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的精度。这个功能只是为了更准确地帮助它。