Precision String Format Specifier In Swift

Swift

Swift Problem Overview


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 and the eBook but haven't been able to figure it out. Thanks!

Swift Solutions


Solution 1 - Swift

The following code:

import Foundation // required for String(format: _, _)

print(String(format: "a float number: %.2f", 1.0321))

will output:

a float number: 1.03

Solution 2 - Swift

My best solution so far, following from David's response:

import Foundation

extension Int {
    func format(f: String) -> String {
        return String(format: "%\(f)d", self)
    }
}

extension Double {
    func format(f: String) -> String {
        return String(format: "%\(f)f", self)
    }
}

let someInt = 4, someIntFormat = "03"
println("The integer number \(someInt) formatted with \"\(someIntFormat)\" looks like \(someInt.format(someIntFormat))")
// The integer number 4 formatted with "03" looks like 004

let someDouble = 3.14159265359, someDoubleFormat = ".3"
println("The floating point number \(someDouble) formatted with \"\(someDoubleFormat)\" looks like \(someDouble.format(someDoubleFormat))")
// The floating point number 3.14159265359 formatted with ".3" looks like 3.142

I think this is the most Swift-like solution, tying the formatting operations directly to the data type. It may well be that there is a built-in library of formatting operations somewhere, or maybe it will be released soon. Keep in mind that the language is still in beta.

Solution 3 - Swift

I found String.localizedStringWithFormat to work quite well:

Example:

let value: Float = 0.33333
let unit: String = "mph"

yourUILabel.text = String.localizedStringWithFormat("%.2f %@", value, unit)

Solution 4 - Swift

This is a very fast and simple way who doesn't need complex solution.

let duration = String(format: "%.01f", 3.32323242)
// result = 3.3

Solution 5 - Swift

Most answers here are valid. However, in case you will format the number often, consider extending the Float class to add a method that returns a formatted string. See example code below. This one achieves the same goal by using a number formatter and extension.

extension Float {
    func string(fractionDigits:Int) -> String {
        let formatter = NSNumberFormatter()
        formatter.minimumFractionDigits = fractionDigits
        formatter.maximumFractionDigits = fractionDigits
        return formatter.stringFromNumber(self) ?? "\(self)"
    }
}

let myVelocity:Float = 12.32982342034

println("The velocity is \(myVelocity.string(2))")
println("The velocity is \(myVelocity.string(1))")

The console shows:

The velocity is 12.33
The velocity is 12.3

SWIFT 3.1 update

extension Float {
    func string(fractionDigits:Int) -> String {
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = fractionDigits
        formatter.maximumFractionDigits = fractionDigits
        return formatter.string(from: NSNumber(value: self)) ?? "\(self)"
    }
}

Solution 6 - Swift

You can't do it (yet) with string interpolation. Your best bet is still going to be NSString formatting:

println(NSString(format:"%.2f", sqrt(2.0)))

Extrapolating from python, it seems like a reasonable syntax might be:

@infix func % (value:Double, format:String) -> String {
    return NSString(format:format, value)
}

Which then allows you to use them as:

M_PI % "%5.3f"                // "3.142"

You can define similar operators for all of the numeric types, unfortunately I haven't found a way to do it with generics.

Swift 5 Update

As of at least Swift 5, String directly supports the format: initializer, so there's no need to use NSString and the @infix attribute is no longer needed which means the samples above should be written as:

println(String(format:"%.2f", sqrt(2.0)))

func %(value:Double, format:String) -> String {
    return String(format:format, value)
}

Double.pi % "%5.3f"         // "3.142"

Solution 7 - Swift

Why make it so complicated? You can use this instead:

import UIKit
 
let PI = 3.14159265359
 
round( PI ) // 3.0 rounded to the nearest decimal
round( PI * 100 ) / 100 //3.14 rounded to the nearest hundredth
round( PI * 1000 ) / 1000 // 3.142 rounded to the nearest thousandth

See it work in Playground.

PS: Solution from: http://rrike.sh/xcode/rounding-various-decimal-places-swift/

Solution 8 - Swift

import Foundation

extension CGFloat {
	var string1: String {
		return String(format: "%.1f", self)
	}
	var string2: String {
		return String(format: "%.2f", self)
	}
}

Usage

let offset = CGPoint(1.23, 4.56)
print("offset: \(offset.x.string1) x \(offset.y.string1)")
// offset: 1.2 x 4.6

Solution 9 - Swift

A more elegant and generic solution is to rewrite ruby / python % operator:

// Updated for beta 5
func %(format:String, args:[CVarArgType]) -> String {
    return NSString(format:format, arguments:getVaList(args))
}

"Hello %@, This is pi : %.2f" % ["World", M_PI]

Solution 10 - Swift

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<T: Numeric>(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<T: Numeric>(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

Solution 11 - Swift

Swift 4

let string = String(format: "%.2f", locale: Locale.current, arguments: 15.123)

Solution 12 - Swift

You can still use NSLog in Swift as in Objective-C just without the @ sign.

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

Edit: After working with Swift since a while I would like to add also this variation

    var r=1.2
    var g=1.3
    var b=1.4
    NSLog("\(r) \(g) \(b)")

Output:

2014-12-07 21:00:42.128 MyApp[1626:60b] 1.2 1.3 1.4

Solution 13 - Swift

extension Double {
  func formatWithDecimalPlaces(decimalPlaces: Int) -> Double {
     let formattedString = NSString(format: "%.\(decimalPlaces)f", self) as String
     return Double(formattedString)!
     }
 }

 1.3333.formatWithDecimalPlaces(2)

Solution 14 - Swift

The answers given so far that have received the most votes are relying on NSString methods and are going to require that you have imported Foundation.

Having done that, though, you still have access to NSLog.

So I think the answer to the question, if you are asking how to continue using NSLog in Swift, is simply:

import Foundation

Solution 15 - Swift

//It will more help, by specify how much decimal Point you want.
let decimalPoint = 2
let floatAmount = 1.10001
let amountValue = String(format: "%0.*f", decimalPoint, floatAmount)

Solution 16 - Swift

After iOS 15+ this solution is recommended:

2.31234.formatted(.number.precision(.fractionalLength(1)))

Solution 17 - Swift

here a "pure" swift solution

 var d = 1.234567
operator infix ~> {}
@infix func ~> (left: Double, right: Int) -> String {
	if right == 0 {
		return "\(Int(left))"
	}
	var k = 1.0
	for i in 1..right+1 {
		k = 10.0 * k
	}
	let n = Double(Int(left*k)) / Double(k)
	return "\(n)"
}
println("\(d~>2)")
println("\(d~>1)")
println("\(d~>0)")

Solution 18 - Swift

Power of extension

extension Double {
    var asNumber:String {
        if self >= 0 {
            var formatter = NSNumberFormatter()
            formatter.numberStyle = .NoStyle
            formatter.percentSymbol = ""
            formatter.maximumFractionDigits = 1
            return "\(formatter.stringFromNumber(self)!)"
        }
        return ""
    }
}

let velocity:Float = 12.32982342034

println("The velocity is \(velocity.toNumber)")

Output: The velocity is 12.3

Solution 19 - Swift

less typing way:

func fprint(format: String, _ args: CVarArgType...) {
    print(NSString(format: format, arguments: getVaList(args)))
}

Solution 20 - Swift

What about extensions on Double and CGFloat types:

extension Double {
   
   func formatted(_ decimalPlaces: Int?) -> String {
      let theDecimalPlaces : Int
      if decimalPlaces != nil {
         theDecimalPlaces = decimalPlaces!
      }
      else {
         theDecimalPlaces = 2
      }
      let theNumberFormatter = NumberFormatter()
      theNumberFormatter.formatterBehavior = .behavior10_4
      theNumberFormatter.minimumIntegerDigits = 1
      theNumberFormatter.minimumFractionDigits = 1
      theNumberFormatter.maximumFractionDigits = theDecimalPlaces
      theNumberFormatter.usesGroupingSeparator = true
      theNumberFormatter.groupingSeparator = " "
      theNumberFormatter.groupingSize = 3
      
      if let theResult = theNumberFormatter.string(from: NSNumber(value:self)) {
         return theResult
      }
      else {
         return "\(self)"
      }
   }
}

Usage:

let aNumber: Double = 112465848348508.458758344
Swift.print("The number: \(aNumber.formatted(2))")

prints: 112 465 848 348 508.46

Solution 21 - Swift

You can also create an operator in this way

operator infix <- {}

func <- (format: String, args:[CVarArg]) -> String {
    return String(format: format, arguments: args)
}

let str = "%d %.1f" <- [1453, 1.123]

Solution 22 - Swift

Also with rounding:

extension Float
{
    func format(f: String) -> String
    {
        return NSString(format: "%\(f)f", self)
    }
    mutating func roundTo(f: String)
    {
        self = NSString(format: "%\(f)f", self).floatValue
    }
}

extension Double
{
    func format(f: String) -> String
    {
        return NSString(format: "%\(f)f", self)
    }
    mutating func roundTo(f: String)
    {
        self = NSString(format: "%\(f)f", self).doubleValue
    }
}

x = 0.90695652173913
x.roundTo(".2")
println(x) //0.91

Solution 23 - Swift

use below method

let output = String.localizedStringWithFormat(" %.02f %.02f %.02f", r, g, b)

println(output)

Solution 24 - Swift

A version of Vincent Guerci's ruby / python % operator, updated for Swift 2.1:

func %(format:String, args:[CVarArgType]) -> String {
  return String(format:format, arguments:args)
}

"Hello %@, This is pi : %.2f" % ["World", M_PI]

Solution 25 - Swift

Plenty of good answers above, but sometimes a pattern is more appropriate than the "%.3f" sort of gobbledygook. Here's my take using a NumberFormatter in Swift 3.

extension Double {
  func format(_ pattern: String) -> String {
    let formatter = NumberFormatter()
    formatter.format = pattern
    return formatter.string(from: NSNumber(value: self))!
  }    
}

let n1 = 0.350, n2 = 0.355
print(n1.format("0.00#")) // 0.35
print(n2.format("0.00#")) // 0.355

Here I wanted 2 decimals to be always shown, but the third only if it wasn't zero.

Solution 26 - Swift

Swift 4 Xcode 10 Update

extension Double {
    var asNumber:String {
        if self >= 0 {
            let formatter = NumberFormatter()
            formatter.numberStyle = .none
            formatter.percentSymbol = ""
            formatter.maximumFractionDigits = 2
            return "\(formatter.string(from: NSNumber(value: self)) ?? "")"
        }
        return ""
    }
}

Solution 27 - Swift

@infix func ^(left:Double, right: Int) -> NSNumber {
    let nf = NSNumberFormatter()
    nf.maximumSignificantDigits = Int(right)
    return  nf.numberFromString(nf.stringFromNumber(left))
}


let r = 0.52264
let g = 0.22643
let b = 0.94837

println("this is a color: \(r^3) \(g^3) \(b^3)")

// this is a color: 0.523 0.226 0.948

Solution 28 - Swift

I don't know about two decimal places, but here's how you can print floats with zero decimal places, so I'd imagine that can be 2 place, 3, places ... (Note: you must convert CGFloat to Double to pass to String(format:) or it will see a value of zero)

func logRect(r: CGRect, _ title: String = "") {
    println(String(format: "[ (%.0f, %.0f), (%.0f, %.0f) ] %@",
        Double(r.origin.x), Double(r.origin.y), Double(r.size.width), Double(r.size.height), title))
}

Solution 29 - Swift

Swift2 example: Screen width of iOS device formatting the Float removing the decimal

print(NSString(format: "Screen width = %.0f pixels", CGRectGetWidth(self.view.frame)))

Solution 30 - Swift

@Christian Dietrich:

instead of:

var k = 1.0
    for i in 1...right+1 {
        k = 10.0 * k
    }
let n = Double(Int(left*k)) / Double(k)
return "\(n)"

it could also be:

let k = pow(10.0, Double(right))
let n = Double(Int(left*k)) / k
return "\(n)"

[correction:] Sorry for confusion* - Of course this works with Doubles. I think, most practical (if you want digits to be rounded, not cut off) it would be something like that:

infix operator ~> {}
func ~> (left: Double, right: Int) -> Double {
    if right <= 0 {
        return round(left)
    }
    let k = pow(10.0, Double(right))
    return round(left*k) / k
}

For Float only, simply replace Double with Float, pow with powf and round with roundf.
Update: I found that it is most practical to use return type Double instead of String. It works the same for String output, i.e.:

println("Pi is roughly \(3.1415926 ~> 3)")

prints: Pi is roughly 3.142
So you can use it the same way for Strings (you can even still write: println(d ~> 2)), but additionally you can also use it to round values directly, i.e.:

d = Double(slider.value) ~> 2

or whatever you need …

Solution 31 - Swift

use

CGFloat 

or

Float.roundTo(places:2)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3524868View Question on Stackoverflow
Solution 1 - SwiftrealityoneView Answer on Stackoverflow
Solution 2 - SwiftAnton TcholakovView Answer on Stackoverflow
Solution 3 - SwiftValentinView Answer on Stackoverflow
Solution 4 - SwiftfatihyildizhanView Answer on Stackoverflow
Solution 5 - SwiftDonnView Answer on Stackoverflow
Solution 6 - SwiftDavid BerryView Answer on Stackoverflow
Solution 7 - SwiftSteyn ViljoenView Answer on Stackoverflow
Solution 8 - SwiftneoneyeView Answer on Stackoverflow
Solution 9 - SwiftVincent GuerciView Answer on Stackoverflow
Solution 10 - SwiftVasily BodnarchukView Answer on Stackoverflow
Solution 11 - Swiftonmyway133View Answer on Stackoverflow
Solution 12 - SwiftholView Answer on Stackoverflow
Solution 13 - SwiftLucas FarahView Answer on Stackoverflow
Solution 14 - SwiftfqdnView Answer on Stackoverflow
Solution 15 - SwiftRavi KumarView Answer on Stackoverflow
Solution 16 - SwiftTiago AlmeidaView Answer on Stackoverflow
Solution 17 - SwiftChristian DietrichView Answer on Stackoverflow
Solution 18 - SwiftMuhammad Aamir AliView Answer on Stackoverflow
Solution 19 - SwiftpeakView Answer on Stackoverflow
Solution 20 - SwiftM WilmView Answer on Stackoverflow
Solution 21 - SwiftotelloView Answer on Stackoverflow
Solution 22 - SwiftChikabuZView Answer on Stackoverflow
Solution 23 - SwiftRamkumar chintalaView Answer on Stackoverflow
Solution 24 - SwiftPaul KingView Answer on Stackoverflow
Solution 25 - SwiftAlexTView Answer on Stackoverflow
Solution 26 - SwiftLeanid VoukView Answer on Stackoverflow
Solution 27 - Swiftuser3778351View Answer on Stackoverflow
Solution 28 - SwiftclearlightView Answer on Stackoverflow
Solution 29 - SwiftGunnar Forsgren - MobimationView Answer on Stackoverflow
Solution 30 - SwiftStuepfnickView Answer on Stackoverflow
Solution 31 - SwiftNicsonView Answer on Stackoverflow