Precision String Format Specifier In Swift

前端 未结 30 2587
面向向阳花
面向向阳花 2020-11-22 05:58

Below is how I would have previously truncated a float to two decimal places

NSLog(@\" %.02f %.02f %.02f\", r, g, b);

I checked the docs an

30条回答
  •  庸人自扰
    2020-11-22 06:12

    Details

    • Xcode 9.3, Swift 4.1
    • Xcode 10.2.1 (10E1001), Swift 5

    Solution 1

    func rounded() -> Double

    (5.2).rounded()
    // 5.0
    (5.5).rounded()
    // 6.0
    (-5.2).rounded()
    // -5.0
    (-5.5).rounded()
    // -6.0
    

    func rounded(_ rule: FloatingPointRoundingRule) -> Double

    let x = 6.5
    
    // Equivalent to the C 'round' function:
    print(x.rounded(.toNearestOrAwayFromZero))
    // Prints "7.0"
    
    // Equivalent to the C 'trunc' function:
    print(x.rounded(.towardZero))
    // Prints "6.0"
    
    // Equivalent to the C 'ceil' function:
    print(x.rounded(.up))
    // Prints "7.0"
    
    // Equivalent to the C 'floor' function:
    print(x.rounded(.down))
    // Prints "6.0"
    

    mutating func round()

    var x = 5.2
    x.round()
    // x == 5.0
    var y = 5.5
    y.round()
    // y == 6.0
    var z = -5.5
    z.round()
    // z == -6.0
    

    mutating func round(_ rule: FloatingPointRoundingRule)

    // Equivalent to the C 'round' function:
    var w = 6.5
    w.round(.toNearestOrAwayFromZero)
    // w == 7.0
    
    // Equivalent to the C 'trunc' function:
    var x = 6.5
    x.round(.towardZero)
    // x == 6.0
    
    // Equivalent to the C 'ceil' function:
    var y = 6.5
    y.round(.up)
    // y == 7.0
    
    // Equivalent to the C 'floor' function:
    var z = 6.5
    z.round(.down)
    // z == 6.0
    

    Solution 2

    extension Numeric {
    
        private func _precision(number: NSNumber, formatter: NumberFormatter) -> Self? {
            if  let formatedNumString = formatter.string(from: number),
                let formatedNum = formatter.number(from: formatedNumString) {
                    return formatedNum as? Self
            }
            return nil
        }
    
        private func toNSNumber() -> NSNumber? {
            if let num = self as? NSNumber { return num }
            guard let string = self as? String, let double = Double(string) else { return nil }
            return NSNumber(value: double)
        }
    
        func precision(_ minimumFractionDigits: Int,
                       roundingMode: NumberFormatter.RoundingMode = NumberFormatter.RoundingMode.halfUp) -> Self? {
            guard let number = toNSNumber() else { return nil }
            let formatter = NumberFormatter()
            formatter.minimumFractionDigits = minimumFractionDigits
            formatter.roundingMode = roundingMode
            return _precision(number: number, formatter: formatter)
        }
    
        func precision(with numberFormatter: NumberFormatter) -> String? {
            guard let number = toNSNumber() else { return nil }
            return numberFormatter.string(from: number)
        }
    }
    

    Usage

    _ = 123.44.precision(2)
    _ = 123.44.precision(3, roundingMode: .up)
    
    let numberFormatter = NumberFormatter()
    numberFormatter.minimumFractionDigits = 1
    numberFormatter.groupingSeparator = " "
    let num = 222.3333
    _ = num.precision(2)
    

    Full sample

    func option1(value: T, numerFormatter: NumberFormatter? = nil) {
        print("Type: \(type(of: value))")
        print("Original Value: \(value)")
        let value1 = value.precision(2)
        print("value1 = \(value1 != nil ? "\(value1!)" : "nil")")
        let value2 = value.precision(5)
        print("value2 = \(value2 != nil ? "\(value2!)" : "nil")")
        if let value1 = value1, let value2 = value2 {
            print("value1 + value2 = \(value1 + value2)")
        }
        print("")
    }
    
    func option2(value: T, numberFormatter: NumberFormatter) {
        print("Type: \(type(of: value))")
        print("Original Value: \(value)")
        let value1 = value.precision(with: numberFormatter)
        print("formated value = \(value1 != nil ? "\(value1!)" : "nil")\n")
    }
    
    func test(with double: Double) {
        print("===========================\nTest with: \(double)\n")
        let float = Float(double)
        let float32 = Float32(double)
        let float64 = Float64(double)
        let float80 = Float80(double)
        let cgfloat = CGFloat(double)
    
        // Exapmle 1
        print("-- Option1\n")
        option1(value: double)
        option1(value: float)
        option1(value: float32)
        option1(value: float64)
        option1(value: float80)
        option1(value: cgfloat)
    
        // Exapmle 2
    
        let numberFormatter = NumberFormatter()
        numberFormatter.formatterBehavior = .behavior10_4
        numberFormatter.minimumIntegerDigits = 1
        numberFormatter.minimumFractionDigits = 4
        numberFormatter.maximumFractionDigits = 9
        numberFormatter.usesGroupingSeparator = true
        numberFormatter.groupingSeparator = " "
        numberFormatter.groupingSize = 3
    
        print("-- Option 2\n")
        option2(value: double, numberFormatter: numberFormatter)
        option2(value: float, numberFormatter: numberFormatter)
        option2(value: float32, numberFormatter: numberFormatter)
        option2(value: float64, numberFormatter: numberFormatter)
        option2(value: float80, numberFormatter: numberFormatter)
        option2(value: cgfloat, numberFormatter: numberFormatter)
    }
    
    test(with: 123.22)
    test(with: 1234567890987654321.0987654321)
    

    Output

    ===========================
    Test with: 123.22
    
    -- Option1
    
    Type: Double
    Original Value: 123.22
    value1 = 123.22
    value2 = 123.22
    value1 + value2 = 246.44
    
    Type: Float
    Original Value: 123.22
    value1 = nil
    value2 = nil
    
    Type: Float
    Original Value: 123.22
    value1 = nil
    value2 = nil
    
    Type: Double
    Original Value: 123.22
    value1 = 123.22
    value2 = 123.22
    value1 + value2 = 246.44
    
    Type: Float80
    Original Value: 123.21999999999999886
    value1 = nil
    value2 = nil
    
    Type: CGFloat
    Original Value: 123.22
    value1 = 123.22
    value2 = 123.22
    value1 + value2 = 246.44
    
    -- Option 2
    
    Type: Double
    Original Value: 123.22
    formatted value = 123.2200
    
    Type: Float
    Original Value: 123.22
    formatted value = 123.220001221
    
    Type: Float
    Original Value: 123.22
    formatted value = 123.220001221
    
    Type: Double
    Original Value: 123.22
    formatted value = 123.2200
    
    Type: Float80
    Original Value: 123.21999999999999886
    formatted value = nil
    
    Type: CGFloat
    Original Value: 123.22
    formatted value = 123.2200
    
    ===========================
    Test with: 1.2345678909876544e+18
    
    -- Option1
    
    Type: Double
    Original Value: 1.2345678909876544e+18
    value1 = 1.23456789098765e+18
    value2 = 1.23456789098765e+18
    value1 + value2 = 2.4691357819753e+18
    
    Type: Float
    Original Value: 1.234568e+18
    value1 = nil
    value2 = nil
    
    Type: Float
    Original Value: 1.234568e+18
    value1 = nil
    value2 = nil
    
    Type: Double
    Original Value: 1.2345678909876544e+18
    value1 = 1.23456789098765e+18
    value2 = 1.23456789098765e+18
    value1 + value2 = 2.4691357819753e+18
    
    Type: Float80
    Original Value: 1234567890987654400.0
    value1 = nil
    value2 = nil
    
    Type: CGFloat
    Original Value: 1.2345678909876544e+18
    value1 = 1.23456789098765e+18
    value2 = 1.23456789098765e+18
    value1 + value2 = 2.4691357819753e+18
    
    -- Option 2
    
    Type: Double
    Original Value: 1.2345678909876544e+18
    formatted value = 1 234 567 890 987 650 000.0000
    
    Type: Float
    Original Value: 1.234568e+18
    formatted value = 1 234 567 939 550 610 000.0000
    
    Type: Float
    Original Value: 1.234568e+18
    formatted value = 1 234 567 939 550 610 000.0000
    
    Type: Double
    Original Value: 1.2345678909876544e+18
    formatted value = 1 234 567 890 987 650 000.0000
    
    Type: Float80
    Original Value: 1234567890987654400.0
    formatted value = nil
    
    Type: CGFloat
    Original Value: 1.2345678909876544e+18
    formatted value = 1 234 567 890 987 650 000.0000
    

提交回复
热议问题