大数运算

大数运算

Posted by HuberyYang on January 1, 2020

由于 Int、Float、Double、CGFloat 都有相应的数值范围或精度限制,所以遇到较大数值计算时,可能导致计算结果数值溢出、精度丢失;使用 ‘NSDecimalNumber’ 可以避免出现上述情况

NSDecimalNumber 文档中的定义

An object for representing and performing arithmetic on base-10 numbers that bridges to Decimal; use NSDecimalNumber when you need reference semantics or other Foundation-specific behavior.

使用实例

swift 比较侧重面向协议,可以通过协议扩展 IntFloatDoubleCGFloatStringNSDecimalNumber 计算方法

  • 声明协议
     public protocol DecimalCalculation {
         // 加
         func decimalAdd(number: Self) -> String
         // 减
         func decimalSubtracting(number: Self) -> String
         // 乘
         func decimalMultiplying(number: Self) -> String
         // 除
         func decimalDividing(number: Self) -> String
     }
    
  • 实现协议的方法
     public extension DecimalCalculation {
    	   
         // 加
         func decimalAdd(number: Self) -> String {
             return decimalCalculate(type: .add, number: number)
         }
    		   
         // 减
         func decimalSubtracting(number: Self) -> String {
             return decimalCalculate(type: .subtracting, number: number)
         }
    		   
         // 乘
         func decimalMultiplying(number: Self) -> String {
             return decimalCalculate(type: .multiplying, number: number)
         }
    		   
         // 除
         func decimalDividing(number: Self) -> String {
             return decimalCalculate(type: .dividing, number: number)
         }
    		   
         private func decimalCalculate(type: DecimalCalculateType, number: Self) -> String {
    		      
             let firstNum = "\(self)"
             let secondNum = "\(number)"
    			      
             let firstDecimalNumber = NSDecimalNumber(string: firstNum)
             let secondDecimalNumber = NSDecimalNumber(string: secondNum)
    			      
    			       
             switch type {
             case .add:
                 return firstDecimalNumber.adding(secondDecimalNumber).stringValue
             case .subtracting:
                 return firstDecimalNumber.subtracting(secondDecimalNumber).stringValue
             case .multiplying:
                 return firstDecimalNumber.multiplying(by: secondDecimalNumber).stringValue
             case .dividing:
                 if secondDecimalNumber.isEqual(to: NSNumber(0)) {
                     return "被除数不能为0"
                 }
                 return firstDecimalNumber.dividing(by: secondDecimalNumber).stringValue
             }
         }
     }
    
  • 遵守协议
     extension String: DecimalCalculation {}
     extension CGFloat: DecimalCalculation {}
     extension Double: DecimalCalculation {}
     extension Float: DecimalCalculation {}
     extension Int: DecimalCalculation {}
    
  • For Example
     // Float 的有效数字只有 6 ~ 7 位
     let p1: Float = 834567.8
     let p2: Float = 967889.5
    	        
     let add = p1.decimalAdd(number: p2)
     let subtracting = p1.decimalSubtracting(number: p2)
     let multiplying = p1.decimalMultiplying(number: p2)
     let dividing = p1.decimalDividing(number: p2)
    		
     print("p1 = \(p1)")
     print("p2 = \(p2)")
     print("add = \(add)")
     print("subtracting = \(subtracting)")
     print("multiplying = \(multiplying)")
     print("dividing = \(dividing)")
    

    计算结果:

     p1 = 834567.8
     p2 = 967889.5
     add = 1802457.3
     subtracting = -133321.7
     multiplying = 807769410658.1
     dividing = 0.86225524711240281044478734400982756812