前言
在开发项目中,我们或多或少都会有金钱方面的计算,如果使用Double
或Float
的话会有精确度问题,因此,苹果提供了NSDecimalNumber
这个API
,下面我们你就来使用它
1、 NSDecimalNumber
NSDecimalNumber
是一种精确计算,主要解决一下问题:
1、字符串转float等不精确问题。
2、精确计算
3、保留小数位数
4、四舍五入及其它的保留小数位数规则
2、 NSDecimalNumber使用
String
转NSDecimalNumber
let decimalNumber = NSDecimalNumber(string: "0.123")
- 加法计算
let decimalNumber1 = NSDecimalNumber(string: "321.321")
let decimalNumber2 = NSDecimalNumber(string: "123.123")
let sum = decimalNumber1.adding(decimalNumber2)
debugPrint(sum)
输出:444.444
- 减法计算
let decimalNumber1 = NSDecimalNumber(string: "321.321")
let decimalNumber2 = NSDecimalNumber(string: "123.123")
let subtracting = decimalNumber1.subtracting(decimalNumber2)
debugPrint(subtracting)
输出:198.198
- 乘法计算
let decimalNumber1 = NSDecimalNumber(string: "321.321")
let decimalNumber2 = NSDecimalNumber(string: "123.123")
let multiplying = decimalNumber1.multiplying(by: decimalNumber2)
debugPrint(multiplying)
输出:39562.005483
- 除法计算
let decimalNumber1 = NSDecimalNumber(string: "321.321")
let decimalNumber2 = NSDecimalNumber(string: "123.123")
let dividing = decimalNumber1.dividing(by: decimalNumber2)
debugPrint(dividing)
输出:2.60975609756097560975609756097560975609
- 每次都这样写的话有点麻烦,我们给
NSDecimalNumber
添加四个扩展+
、-
、*
、/
public extension NSDecimalNumber {
static func + (lhs: NSDecimalNumber, rhs: NSDecimalNumber) -> NSDecimalNumber {
return lhs.adding(rhs)
}
static func - (lhs: NSDecimalNumber, rhs: NSDecimalNumber) -> NSDecimalNumber {
return lhs.subtracting(rhs)
}
static func * (lhs: NSDecimalNumber, rhs: NSDecimalNumber) -> NSDecimalNumber {
return lhs.multiplying(by: rhs)
}
static func / (lhs: NSDecimalNumber, rhs: NSDecimalNumber) -> NSDecimalNumber {
return lhs.dividing(by: rhs)
}
}
这样直接使用+
、-
、*
、/
就可以了
let sum = decimalNumber1 + decimalNumber2
let subtracting = decimalNumber1 - decimalNumber2
let multiplying = decimalNumber1 * decimalNumber2
let dividing = decimalNumber1 / decimalNumber2
- 如果我们想要保留几位小数点该怎么弄呢?我们可以使用
NSDecimalNumberHandler
,下面是初始化方法
public init(roundingMode: NSDecimalNumber.RoundingMode, scale: Int16, raiseOnExactness exact: Bool, raiseOnOverflow overflow: Bool, raiseOnUnderflow underflow: Bool, raiseOnDivideByZero divideByZero: Bool)
我们可以看到里面有一个RoundingMode
枚举
public enum RoundingMode : UInt {
case plain = 0
case down = 1
case up = 2
case bankers = 3
}
其中4个值的大致意思是:
plain: 保留位数的下一位四舍五入
down: 保留位数的下一位直接舍去
up: 保留位数的下一位直接进一位
bankers: 当保留位数的下一位不是5时,四舍五入,当保留位数的下一位是5时,其前一位是偶数直接舍去,是奇数直接进位(如果5后面还有数字则直接进位)
我们使用第一个plain
来试一下,保留两位小数,其中scale
就是精确到几位小数
let decimalNumber1 = NSDecimalNumber(string: "321.321")
let decimalNumber2 = NSDecimalNumber(string: "123.123")
let sum = decimalNumber1.adding(decimalNumber2)
let behavior = NSDecimalNumberHandler(roundingMode: .plain, scale: Int16(2), raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: true)
debugPrint(product.stringValue)
输出:444.44
- 接下来给
NSDecimalNumber
扩展一个转String
的方法
public extension NSDecimalNumber {
/// 转String 四舍五入
/// - Parameter scale: 保留几位小数
/// - Parameter roundingMode:
/// plain: 保留位数的下一位四舍五入
/// down: 保留位数的下一位直接舍去
/// up: 保留位数的下一位直接进一位
/// bankers: 当保留位数的下一位不是5时,四舍五入,当保留位数的下一位是5时,其前一位是偶数直接舍去,是奇数直接进位(如果5后面还有数字则直接进位)
func toString(_ scale: Int = 2,
roundingMode: RoundingMode = .plain) -> String {
let behavior = NSDecimalNumberHandler(
roundingMode: roundingMode,
scale: Int16(scale),
raiseOnExactness: false,
raiseOnOverflow: false,
raiseOnUnderflow: false,
raiseOnDivideByZero: true)
let product = multiplying(by: .one, withBehavior: behavior)
return product.stringValue
}
}