快速回合问题
我有这个信息。
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(你可以设置一个默认值来使用)。
好的东西阅读:
- http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/
- https://gist.github.com/RonJeffries/009495abec81b2b1890b(Swift便捷function仅用于示例目的)
- https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDecimalNumber_Class/index.html
我认为游乐场显示出一个意想不到的结果,因为它显示之前强制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只是帮助它更准确一点。
- 我如何检查移动数据或无线networking打开或closures。 ios迅速
- UIAlertcontroller在Swift中显示时保持键盘是否打开?
- Swift – 如何获取iPhone上的所有照片和video列表?
- ios – Swift – dequeueReusableCellWithReuseIdentifier,collectionViewController的单元格(在UIView中)滚动后不会加载
- 从Xcode 7 UItesting目标访问主机应用程序代码
- ios快速共享扩展:处理图像的最佳方式是什么?
- 仅适用于iOS 10的Swift 3中的NSBatchDeleteRequest?
- Swift Optionals – 不同的展开方式
- 如何通过asynchronous或静态调用实现强大的保留循环?