This is the 22nd day of my participation in the August Wen Challenge.More challenges in August

preface

In our development projects, we more or less always do calculations in terms of money, and there are precision issues if you use Double or Float, so Apple provides an API called NSDecimalNumber, which we’ll use for you

1、 NSDecimalNumber

NSDecimalNumber is an exact calculation to solve the problem:

1, string to float and other imprecise problems. 2, accurate calculation 3, reserving decimals 4, rounding and other reserving decimals rulesCopy the code

2. Use NSDecimalNumber

  • StringturnNSDecimalNumber
Let decimalNumber = NSDecimalNumber(string: "0.123")Copy the code
  • addition
Let decimalNumber1 = NSDecimalNumber(string: "321.321") Let decimalNumber2 = NSDecimalNumber(string: "123.123") let sum = decimalNumber1. Adding (decimalNumber2) debugPrint(sum) 444.444Copy the code
  • Subtraction calculation
Let decimalNumber1 = NSDecimalNumber(string: "321.321") Let decimalNumber2 = NSDecimalNumber(string: "123.123") let subtracting = decimalNumber1. Subtracting (decimalNumber2) debugPrint (subtracting) output: 198.198Copy the code
  • The multiplication calculation
Let decimalNumber1 = NSDecimalNumber(string: "321.321") Let decimalNumber2 = NSDecimalNumber(string: "123.123") let multiplying = decimalNumber1. Multiplying (by: decimalNumber2) debugPrint (multiplying) output: 39562.005483Copy the code
  • Division calculation
Let decimalNumber1 = NSDecimalNumber(string: "321.321") Let decimalNumber2 = NSDecimalNumber(string: "123.123") Let dividing = decimalNumber1. DecimalNumber2) debugPrint (dividing) output: 2.60975609756097560975609756097560975609Copy the code
  • It’s a little bit troublesome to write it like this every time, so let’s giveNSDecimalNumberAdd four extensions+,-,*,/
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)
    }
}
Copy the code

Use +, -, *, / directly

let sum = decimalNumber1 + decimalNumber2
let subtracting = decimalNumber1 - decimalNumber2
let multiplying = decimalNumber1 * decimalNumber2
let dividing = decimalNumber1 / decimalNumber2
Copy the code
  • What if we want to keep a few decimal places? We can useNSDecimalNumberHandlerThe following is the initialization method
public init(roundingMode: NSDecimalNumber.RoundingMode, scale: Int16, raiseOnExactness exact: Bool, raiseOnOverflow overflow: Bool, raiseOnUnderflow underflow: Bool, raiseOnDivideByZero divideByZero: Bool)
Copy the code

We can see that there is a RoundingMode enumeration

public enum RoundingMode : UInt {
    case plain = 0
    case down = 1
    case up = 2
    case bankers = 3
}
Copy the code

Four of the values roughly mean:

Plain: the next digit is rounded down: the next digit is rounded down: the next digit is rounded up: the next digit is rounded up: the next digit is rounded up: the next digit is rounded up: the next digit is rounded up: the next digit is rounded up: the next digit is rounded up: the next digit is rounded up by the next bankers: When the next digit of the reserved digit is not 5, the digits are rounded. When the next digit of the reserved digit is 5, the digits preceding the reserved digit are directly rounded. If the digits are odd, the digits are directly rounded.Copy the code

Let’s try using our first plain, with two decimal places reserved, where scale is accurate to a few decimal places

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.44Copy the code
  • Next to theNSDecimalNumberExtend a turnStringThe method of
Public extension NSDecimalNumber {/// -parameter scale: keep some decimals /// -parameter roundingMode: Bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers: bankers RoundingMode: func toString(_ scale: Int = 2, roundingMode: func toString(_ scale: Int = 2, roundingMode: roundingMode: func toString(_ scale: Int = 2, roundingMode: 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 } }Copy the code