Leighton
Leighton

Reputation: 6679

Rounding a double value to x number of decimal places in swift

Can anyone tell me how to round a double value to x number of decimal places in Swift?

I have:

var totalWorkTimeInHours = (totalWorkTime/60/60)

With totalWorkTime being an NSTimeInterval (double) in second.

totalWorkTimeInHours will give me the hours, but it gives me the amount of time in such a long precise number e.g. 1.543240952039......

How do I round this down to, say, 1.543 when I print totalWorkTimeInHours?

Upvotes: 554

Views: 618562

Answers (30)

1156752
1156752

Reputation: 4013

In Swift 5.9 and Xcode 15.2:

let pi: Double = 3.14159265358979
String(format:"%.2f", pi)

Example:

Rounding a double value

PS.: It still the same since Swift 2.0 and Xcode 7.2

Upvotes: 212

Rob
Rob

Reputation: 438122

There are two separate questions:

  1. The accurate internal representation of rounded decimal value

    If you want to round Double values, you might want to use Swift Decimal so you don't introduce any errors that can crop up when trying to math with these rounded values. If you use Decimal, it can accurately represent decimal values of that rounded floating point value.

    So you can do:

    extension Double {
        /// Convert `Double` to `Decimal`, rounding it to `scale` decimal places.
        ///
        /// - Parameters:
        ///   - scale: How many decimal places to round to. Defaults to `0`.
        ///   - mode:  The preferred rounding mode. Defaults to `.plain`.
        /// - Returns: The rounded `Decimal` value.
    
        func roundedDecimal(to scale: Int = 0, mode: NSDecimalNumber.RoundingMode = .plain) -> Decimal {
            var decimalValue = Decimal(self)
            var result = Decimal()
            NSDecimalRound(&result, &decimalValue, scale, mode)
            return result
        }
    }
    

    Then, you can get the rounded Decimal value like so:

    let foo = 1427.3000000002
    let value = foo.roundedDecimal(to: 2)          // results in 1427.30
    

    This concept of using Decimal for the value is essential in financial apps where you do not just want to ignore/hide errors introduced with calculations of binary floating point numbers.

  2. The string representation of a rounded value in the UI

    If you want to display it with a specified number of decimal places (as well as localize the string for the user’s current locale), you can use a NumberFormatter:

    let formatter = NumberFormatter()
    formatter.maximumFractionDigits = 2
    formatter.minimumFractionDigits = 2
    formatter.numberStyle = .decimal
    
    if let string = formatter.string(for: value) {
        print(string)                              // correctly results in “1,427.30” in US; “1.427,30” in Germany
    }
    

    Note, this use of a formatter (notably the localization) is useful both with Decimal values and binary floating point numbers.

    Also note that the above applies to AppKit/UIKit. In SwiftUI, you can use the “specifier” and it will localize and format the string for you:

    Text("Value is \(value, specifier: "%0.2f")") // again, results in “1,427.30” in US; “1.427,30” in Germany
    

Upvotes: 21

Milan Savaliya M
Milan Savaliya M

Reputation: 304

Rounding a double value to x number of decimal places in swift

input = 2.99999999 output = 2.9

input = 2.0 output = 2

print(2.9999.roundDecimal(places: 1)) // This will print "2.9"

print(2.9999.roundDecimal(places: 2)) // This will print "2.99"

extension Double {
    func roundDecimal(places: Int = 2) -> String {
        if self == Double(Int(self)) {
            return "\(Int(self))"
        } else {
            let multiplier = pow(10.0, Double(places))
            let doubleNumber = self
            let integerPart = Int(doubleNumber)
            let decimalPart = Int(doubleNumber * multiplier) % Int(multiplier)
            let combinedString = "\(integerPart).\(decimalPart)"
            return combinedString
        }
    }
}

Upvotes: -1

zisoft
zisoft

Reputation: 23078

You can use Swift's round function to accomplish this.

To round a Double with 3 digits precision, first multiply it by 1000, round it and divide the rounded result by 1000:

let x = 1.23556789
let y = Double(round(1000 * x) / 1000)
print(y) /// 1.236

Unlike any kind of printf(...) or String(format: ...) solutions, the result of this operation is still of type Double.

Regarding the comments that it sometimes does not work, please read this: What Every Programmer Should Know About Floating-Point Arithmetic

Upvotes: 536

Ash
Ash

Reputation: 9351

Building on Yogi's answer, here's a Swift function that does the job:

func roundToPlaces(value:Double, places:Int) -> Double {
    let divisor = pow(10.0, Double(places))
    return round(value * divisor) / divisor
}

As extension with rounding rule:

extension Double {
    /// - returns: Rounded value with specific round rule and precision
    func roundToPlaces(_ rule: FloatingPointRoundingRule? = . toNearestOrEven, precision: Int) -> Double {
        let divisor = pow(10.0, Double(precision))
        return (self * divisor).rounded(rule) / divisor
    }
}

print(0.123456.roundToPlaces(.down, precision: 4)) // 0.1234
print(0.123456.roundToPlaces(.up, precision: 4)) // 0.1235

Upvotes: 36

vadian
vadian

Reputation: 285220

In iOS 15 / macOS 12 new inline number formatters have been introduced.

Without any rounding rule it rounds like taught in school. The syntax

let value = 1.543240
let rounded = value.formatted(.number.precision(.fractionLength(2))))

rounds down to 1.54 and

let value = 1.545240
let rounded = value.formatted(.number.precision(.fractionLength(2))))

rounds up to 1.55, fractionLength specifies the number of fractional digits

To force rounding down add a rounding rule

let rounded = value.formatted(.number.rounded(rule: .down).precision(.fractionLength(2))))

Upvotes: 5

Kingsley Mitchell
Kingsley Mitchell

Reputation: 2589

Swift 4 Best Way

This is what worked for me to round to 2 decimal places

let val = round(100 * scale) / 100

Upvotes: 1

Jeri P.M
Jeri P.M

Reputation: 409

if you want after the comma there is only 0 for the round, try this:

extension Double {
    func isInteger() -> Any {
        let check = floor(self) == self
        if check {
            return Int(self)
        } else {
            return self
        }
    }
}

let toInt: Double = 10.0
let stillDouble: Double = 9.12

print(toInt.isInteger) // 10
print(stillDouble.isInteger) // 9.12

Upvotes: 1

Cable W
Cable W

Reputation: 673

For ease to use, I created an extension:

extension Double {
    var threeDigits: Double {
        return (self * 1000).rounded(.toNearestOrEven) / 1000
    }
    
    var twoDigits: Double {
        return (self * 100).rounded(.toNearestOrEven) / 100
    }
    
    var oneDigit: Double {
        return (self * 10).rounded(.toNearestOrEven) / 10
    }
}

var myDouble = 0.12345
print(myDouble.threeDigits)
print(myDouble.twoDigits)
print(myDouble.oneDigit)

The print results are:

0.123
0.12
0.1

Thanks for the inspiration of other answers!

Upvotes: 8

vedrano
vedrano

Reputation: 2971

For many applications, you need exact number of decimal places to round.

For some others, you do not have such a constraint and want to "compress" output size, but still want to avoid converting number to strings (and vice versa later) like in exporting JSON having millions of numbers.

In that case you may use 'trick' to round significand (mantissa), not whole number. In such a case you will end up with final decimal places and most of numbers will still have at most e.g. 3 decimal places (if needed) preserved while some will have slightly more.

This is what you might expect with this approach while still working with decimal numbers:

5.2472

5.2516

5.2556

5.26

5.264

instead of:

5.24731462499949

5.251488374999099

5.25566283399894

5.259839374999501

5.264012208999702

let value = 5.24731462499949

print(value)
// 5.24731462499949

let valueSignificandRounded = round((1000 * 10) * value.significand) / (1000 * 10)

let valueRounded = CGFloat(sign: v.sign, exponent: v.exponent, significand: valueSignificandRounded)

print(valueRounded)
// 5.2472

Upvotes: 1

Pratik Sodha
Pratik Sodha

Reputation: 3727

The solution worked for me. XCode 13.3.1 & Swift 5

extension Double {
    
    func rounded(decimalPoint: Int) -> Double {
        let power = pow(10, Double(decimalPoint))
       return (self * power).rounded() / power
    }
}

Test:

print(-87.7183123123.rounded(decimalPoint: 3))
print(-87.7188123123.rounded(decimalPoint: 3))
print(-87.7128123123.rounded(decimalPoint: 3))

Result:

-87.718
-87.719
-87.713

Upvotes: 6

Nathan Day
Nathan Day

Reputation: 6037

Lots of example are using maths, the problem is floats are approximations of real number, there is no way to express 0.1 (1/10) exactly as a float just as there is no exact way to express ⅓ exactly using decimal points, so you need to ask your self exactly what your are trying to achieve, if you just want to display them leave them as they are in code, trying to round them is going to justify give you less accurate result as you are throwing away precious, round ⅓ in decimal notation to 1 decimal place is not going to give you a number closer to ⅓, us NumberFormate to round it, if you have something like a viewModel class it can be used to return a string representation to your models numbers. NumberFormaters give you lots of control on how numbers are formatted and the number of decimal places you want.

Upvotes: 1

Lukasz D
Lukasz D

Reputation: 299

Swift 5

using String method

var yourDouble = 3.12345
//to round this to 2 decimal spaces i could turn it into string
let roundingString = String(format: "%.2f", myDouble)
let roundedDouble = Double(roundingString) //and than back to double
// result is 3.12 

but it's more accepted to use extension

extension Double {
    func round(to decimalPlaces: Int) -> Double {
        let precisionNumber = pow(10,Double(decimalPlaces))
        var n = self // self is a current value of the Double that you will round
        n = n * precisionNumber
        n.round()
        n = n / precisionNumber
        return n
    }
}

and then you can use:

yourDouble.round(to:2)

Upvotes: 7

Amais Sheikh
Amais Sheikh

Reputation: 453

var n = 123.111222333
n = Double(Int(n * 10.0)) / 10.0

Result: n = 123.1

Change 10.0 (1 decimal place) to any of 100.0 (2 decimal place), 1000.0 (3 decimal place) and so on, for the number of digits you want after decimal..

Upvotes: 4

Imanou Petit
Imanou Petit

Reputation: 92569

With Swift 5, according to your needs, you can choose one of the 9 following styles in order to have a rounded result from a Double.


#1. Using FloatingPoint rounded() method

In the simplest case, you may use the Double rounded() method.

let roundedValue1 = (0.6844 * 1000).rounded() / 1000
let roundedValue2 = (0.6849 * 1000).rounded() / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685

#2. Using FloatingPoint rounded(_:) method

let roundedValue1 = (0.6844 * 1000).rounded(.toNearestOrEven) / 1000
let roundedValue2 = (0.6849 * 1000).rounded(.toNearestOrEven) / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685

#3. Using Darwin round function

Foundation offers a round function via Darwin.

import Foundation

let roundedValue1 = round(0.6844 * 1000) / 1000
let roundedValue2 = round(0.6849 * 1000) / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685

#4. Using a Double extension custom method built with Darwin round and pow functions

If you want to repeat the previous operation many times, refactoring your code can be a good idea.

import Foundation

extension Double {
    func roundToDecimal(_ fractionDigits: Int) -> Double {
        let multiplier = pow(10, Double(fractionDigits))
        return Darwin.round(self * multiplier) / multiplier
    }
}

let roundedValue1 = 0.6844.roundToDecimal(3)
let roundedValue2 = 0.6849.roundToDecimal(3)
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685

#5. Using NSDecimalNumber rounding(accordingToBehavior:) method

If needed, NSDecimalNumber offers a verbose but powerful solution for rounding decimal numbers.

import Foundation

let scale: Int16 = 3

let behavior = NSDecimalNumberHandler(roundingMode: .plain, scale: scale, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: true)

let roundedValue1 = NSDecimalNumber(value: 0.6844).rounding(accordingToBehavior: behavior)
let roundedValue2 = NSDecimalNumber(value: 0.6849).rounding(accordingToBehavior: behavior)

print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685

#6. Using NSDecimalRound(_:_:_:_:) function

import Foundation

let scale = 3

var value1 = Decimal(0.6844)
var value2 = Decimal(0.6849)

var roundedValue1 = Decimal()
var roundedValue2 = Decimal()

NSDecimalRound(&roundedValue1, &value1, scale, NSDecimalNumber.RoundingMode.plain)
NSDecimalRound(&roundedValue2, &value2, scale, NSDecimalNumber.RoundingMode.plain)

print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685

#7. Using NSString init(format:arguments:) initializer

If you want to return a NSString from your rounding operation, using NSString initializer is a simple but efficient solution.

import Foundation

let roundedValue1 = NSString(format: "%.3f", 0.6844)
let roundedValue2 = NSString(format: "%.3f", 0.6849)
print(roundedValue1) // prints 0.684
print(roundedValue2) // prints 0.685

#8. Using String init(format:_:) initializer

Swift’s String type is bridged with Foundation’s NSString class. Therefore, you can use the following code in order to return a String from your rounding operation:

import Foundation

let roundedValue1 = String(format: "%.3f", 0.6844)
let roundedValue2 = String(format: "%.3f", 0.6849)
print(roundedValue1) // prints 0.684
print(roundedValue2) // prints 0.685

#9. Using NumberFormatter

If you expect to get a String? from your rounding operation, NumberFormatter offers a highly customizable solution.

import Foundation

let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
formatter.roundingMode = NumberFormatter.RoundingMode.halfUp
formatter.maximumFractionDigits = 3

let roundedValue1 = formatter.string(from: 0.6844)
let roundedValue2 = formatter.string(from: 0.6849)
print(String(describing: roundedValue1)) // prints Optional("0.684")
print(String(describing: roundedValue2)) // prints Optional("0.685")

Upvotes: 389

Krunal Patel
Krunal Patel

Reputation: 1691

This is a fully worked code

Swift 3.0/4.0/5.0 , Xcode 9.0 GM/9.2 and above

let doubleValue : Double = 123.32565254455
self.lblValue.text = String(format:"%.f", doubleValue)
print(self.lblValue.text)

output - 123

let doubleValue : Double = 123.32565254455
self.lblValue_1.text = String(format:"%.1f", doubleValue)
print(self.lblValue_1.text)

output - 123.3

let doubleValue : Double = 123.32565254455
self.lblValue_2.text = String(format:"%.2f", doubleValue)
print(self.lblValue_2.text)

output - 123.33

let doubleValue : Double = 123.32565254455
self.lblValue_3.text = String(format:"%.3f", doubleValue)
print(self.lblValue_3.text)

output - 123.326

Upvotes: 61

jaiswal Rajan
jaiswal Rajan

Reputation: 4661

In Swift 3.0 and Xcode 8.0:

extension Double {
    func roundTo(places: Int) -> Double {
        let divisor = pow(10.0, Double(places))
        return (self * divisor).rounded() / divisor
    }
}

Use this extension like so:

let doubleValue = 3.567
let roundedValue = doubleValue.roundTo(places: 2)
print(roundedValue) // prints 3.56

Upvotes: 31

Yervand Saribekyan
Yervand Saribekyan

Reputation: 502

To avoid Float imperfections use Decimal

extension Float {
    func rounded(rule: NSDecimalNumber.RoundingMode, scale: Int) -> Float {
        var result: Decimal = 0
        var decimalSelf = NSNumber(value: self).decimalValue
        NSDecimalRound(&result, &decimalSelf, scale, rule)
        return (result as NSNumber).floatValue
    }
}

ex.
1075.58 rounds to 1075.57 when using Float with scale: 2 and .down
1075.58 rounds to 1075.58 when using Decimal with scale: 2 and .down

Upvotes: 4

OldManMcDonalds
OldManMcDonalds

Reputation: 1167

Here's one for SwiftUI if you need a Text element with the number value.

struct RoundedDigitText : View {
    let digits : Int
    let number : Double

    var body : some View {
        Text(String(format: "%.\(digits)f", number))
    }
}

Upvotes: 2

Matiu Awaiti
Matiu Awaiti

Reputation: 61

This seems to work in Swift 5.

Quite surprised there isn't a standard function for this already.

//Truncation of Double to n-decimal places with rounding

extension Double {

    func truncate(to places: Int) -> Double {
    return Double(Int((pow(10, Double(places)) * self).rounded())) / pow(10, Double(places))
    }

}

Upvotes: 6

George Filippakos
George Filippakos

Reputation: 16569

Use the built in Foundation Darwin library

SWIFT 3

extension Double {
    func round(to places: Int) -> Double {
        let divisor = pow(10.0, Double(places))
        return Darwin.round(self * divisor) / divisor
    }
}

Usage:

let number:Double = 12.987654321
print(number.round(to: 3)) 

Outputs: 12.988

Upvotes: 17

TOUZENE Mohamed Wassim
TOUZENE Mohamed Wassim

Reputation: 712

You can add this extension :

extension Double {
    var clean: String {
        return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(format: "%.2f", self)
    }
}

and call it like this :

let ex: Double = 10.123546789
print(ex.clean) // 10.12

Upvotes: 2

vacawama
vacawama

Reputation: 154691

How do I round this down to, say, 1.543 when I print totalWorkTimeInHours?

To round totalWorkTimeInHours to 3 digits for printing, use the String constructor which takes a format string:

print(String(format: "%.3f", totalWorkTimeInHours))

Upvotes: 493

Naishta
Naishta

Reputation: 12383

Swift 4, Xcode 10

yourLabel.text =  String(format:"%.2f", yourDecimalValue)

Upvotes: 26

staticVoidMan
staticVoidMan

Reputation: 20274

Either:

  1. Using String(format:):

    • Typecast Double to String with %.3f format specifier and then back to Double

      Double(String(format: "%.3f", 10.123546789))!
      
    • Or extend Double to handle N-Decimal places:

      extension Double {
          func rounded(toDecimalPlaces n: Int) -> Double {
              return Double(String(format: "%.\(n)f", self))!
          }
      }
      
  2. By calculation

    • multiply with 10^3, round it and then divide by 10^3...

      (1000 * 10.123546789).rounded()/1000
      
    • Or extend Double to handle N-Decimal places:

      extension Double {    
          func rounded(toDecimalPlaces n: Int) -> Double {
              let multiplier = pow(10, Double(n))
              return (multiplier * self).rounded()/multiplier
          }
      }
      

Upvotes: 10

Davender Verma
Davender Verma

Reputation: 573

//find the distance between two points
let coordinateSource = CLLocation(latitude: 30.7717625, longitude:76.5741449 )
let coordinateDestination = CLLocation(latitude: 29.9810859, longitude: 76.5663599)
let distanceInMeters = coordinateSource.distance(from: coordinateDestination)
let valueInKms = distanceInMeters/1000
let preciseValueUptoThreeDigit = Double(round(1000*valueInKms)/1000)
self.lblTotalDistance.text = "Distance is : \(preciseValueUptoThreeDigit) kms"

Upvotes: 1

Merichle
Merichle

Reputation: 710

The code for specific digits after decimals is:

var a = 1.543240952039
var roundedString = String(format: "%.3f", a)

Here the %.3f tells the swift to make this number rounded to 3 decimal places.and if you want double number, you may use this code:

// String to Double

var roundedString = Double(String(format: "%.3f", b))

Upvotes: 20

Ayman Badr
Ayman Badr

Reputation: 81

round a double value to x number of decimal
NO. of digits after decimal

var x = 1.5657676754
var y = (x*10000).rounded()/10000
print(y)  // 1.5658 

var x = 1.5657676754 
var y = (x*100).rounded()/100
print(y)  // 1.57 

var x = 1.5657676754
var y = (x*10).rounded()/10
print(y)  // 1.6

Upvotes: 8

Sebastian
Sebastian

Reputation: 9051

Extension for Swift 2

A more general solution is the following extension, which works with Swift 2 & iOS 9:

extension Double {
    /// Rounds the double to decimal places value
    func roundToPlaces(places:Int) -> Double {
        let divisor = pow(10.0, Double(places))
        return round(self * divisor) / divisor
    }
}


Extension for Swift 3

In Swift 3 round is replaced by rounded:

extension Double {
    /// Rounds the double to decimal places value
    func rounded(toPlaces places:Int) -> Double {
        let divisor = pow(10.0, Double(places))
        return (self * divisor).rounded() / divisor
    }
}


Example which returns Double rounded to 4 decimal places:

let x = Double(0.123456789).roundToPlaces(4)  // x becomes 0.1235 under Swift 2
let x = Double(0.123456789).rounded(toPlaces: 4)  // Swift 3 version

Upvotes: 497

Abuzar Manzoor
Abuzar Manzoor

Reputation: 409

The best way to format a double property is to use the Apple predefined methods.

mutating func round(_ rule: FloatingPointRoundingRule)

FloatingPointRoundingRule is a enum which has following possibilities

Enumeration Cases:

case awayFromZero Round to the closest allowed value whose magnitude is greater than or equal to that of the source.

case down Round to the closest allowed value that is less than or equal to the source.

case toNearestOrAwayFromZero Round to the closest allowed value; if two values are equally close, the one with greater magnitude is chosen.

case toNearestOrEven Round to the closest allowed value; if two values are equally close, the even one is chosen.

case towardZero Round to the closest allowed value whose magnitude is less than or equal to that of the source.

case up Round to the closest allowed value that is greater than or equal to the source.

var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0

Upvotes: 7

Related Questions