543

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?

Leighton
  • 6,559
  • 7
  • 21
  • 28
  • 2
    See [my answer](http://stackoverflow.com/a/38036978/1966109) to find up to 9 different ways to round a double using Darwin `round(_:)`, `Double` `round()`, `NSString` initializer, `String` initializer, `NumberFormatter`, Double extension or even `NSDecimalNumber` and `Decimal`. – Imanou Petit Feb 07 '18 at 18:10
  • @Rounded, a swift 5.1 property wrapper : https://gist.github.com/abhijithpp/1cc41b41a5d1c8f007da90f20bc0c65f – Abhijith Mar 12 '20 at 14:21

35 Answers35

524

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

MendelG
  • 14,885
  • 4
  • 25
  • 52
zisoft
  • 22,770
  • 10
  • 62
  • 73
  • 1
    For some reasons it doesn't help.. I am using this in the following case TransformOf(fromJSON: {Double(round(($0! as NSString).doubleValue * 100)/100)}, toJSON: {"\($0)"}) – Fawkes Jul 30 '15 at 22:50
  • 41
    Doesn't work for me in playground: ```let rate = 9.94999999999; Double(round(rate * 100) / 100);``` Output: ```9.94999999999, 9.949999999999999``` Only works for print but how can I assign it to variable? – Alexander Yakovlev May 05 '16 at 08:53
  • 1
    You should use Decimal for this, not plain Doubles. – csotiriou Dec 12 '16 at 16:08
  • 33
    "What Every Computer Scientist Should Know About Floating-Point Arithmetic" is 73 pages long. What's the TL;DR on that? :) – JaredH Apr 14 '18 at 21:45
  • @SashaKid what is the solution for your question. I am having the same issue. I can't assign it to a variable – HardikDG Oct 03 '18 at 02:19
  • 2
    @HardikDG I don't remember, sorry :-) – Alexander Yakovlev Oct 04 '18 at 10:59
  • With Double extension, check out this answer: https://stackoverflow.com/a/54372912/7343596 – balazs630 Apr 13 '19 at 12:13
  • @SashaKid Apparently, it works now. Just got 9.95 for your example in a playground. Swift 4. – Kirill Apr 15 '19 at 02:14
  • Awesome, thank you. You can also use it to round to the nearest fraction, here I use it to round to the nearest eighth - let DECIMAL_FIDELITY = 8.0; width = Double(round(DECIMAL_FIDELITY * width) / DECIMAL_FIDELITY ) – Jc Nolan Jan 10 '22 at 23:42
489

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
mrh.is
  • 184
  • 3
  • 13
Sebastian
  • 8,952
  • 3
  • 32
  • 30
  • Added this code to my repo, thanks! https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/DoubleExtensions.swift – Esqarrouth Mar 23 '16 at 12:48
  • 31
    The nature of Swift's Double appears to be that it can be imprecise – because of the way it's stored/accessed in binary, even using this rounding function will not return a number rounded to 3 decimal places: e.g., `round(8.46 * pow(10.0, 3.0)) / pow(10.0, 3.0)` returns `8.460000000000001`. Doing the same with Float, _at least in this scenario_, does in fact seem to work: `round(Float(8.46) * pow(10.0, 3.0)) / pow(10.0, 3.0)` yields `8.46`. Just something worth noting. – Ben Saufley Jul 07 '16 at 21:51
  • 3
    Unfortunately, this no longer works in Swift 3, I am getting this error `No '*' candidates produce the expected contextual result type 'FloatingPointRoundingRule'` – koen Aug 20 '16 at 19:44
  • 3
    I updated the solution and added an extension for Swift 3. – Sebastian Aug 22 '16 at 10:26
  • 3
    To be more swift 3... you should change for func rounded(toPlaces places: Int) -> Double – FouZ Sep 07 '16 at 13:11
  • agree with FouZ. But I think rounded(to places: Int) is much swifty. – Mark Oct 14 '16 at 07:46
  • 3
    @BenSaufley But it also does not work if you enter 98.68. In this case, I get 98.6800003 – Alexander Khitev Dec 21 '16 at 08:31
  • 1
    I like more generic extension for float numbers: `extension FloatingPoint { func roundTo(places:Int) -> Self { let divisor = Self(Int(pow(10.0, Double(places)))) return (self * divisor).rounded() / divisor } }` – Libor Zapletal Mar 19 '17 at 11:02
  • 1
    With this solution, 8.104.rounded(toPlaces: 2) will return 8.1 if displaying it as String, I'll still need to use String(format ...) to display it as 8.10 – code4latte Dec 01 '17 at 18:59
  • Where in my program do I paste this? – Doug Null Jun 24 '21 at 22:31
  • If places is 0 this creates an infinity loop. – ScottyBlades Oct 10 '21 at 20:56
479

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))
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • 36
    That's truncation, not rounding – Eyeball Dec 07 '14 at 08:10
  • 48
    @Eyeball: Actually, it DOES round. It is the same behaviour as the C printf functionality, which rounds to the requested digits. So `String(format: "%.3f", 1.23489)` prints `1.235` – zisoft Dec 07 '14 at 08:30
  • Does this work on a `double` as well? Or only a `float`? – Clifton Labrum Jun 24 '15 at 22:28
  • 9
    The original poster is looking for a numeric value to use, not a string to display. – pr1001 Feb 16 '16 at 17:28
  • 33
    @pr1001, perhaps so, but that wasn't clear at the time and 46 others have found my answer useful. Stack Overflow is more than just helping the OP. – vacawama Feb 16 '16 at 17:44
  • `String(format: "%.1f", 10.45)` prints `10.4` in a playground. – Clifton Labrum May 26 '16 at 23:52
  • @CliftonLabrum, do `String(format: "%.15f", 10.45)` and the truth will be revealed to you. – vacawama May 27 '16 at 00:21
  • 4
    odd, this is returning 0.00 every time. – Eric H Jun 23 '16 at 23:18
  • If you're dividing numbers make sure they're both `Double` and not `Int` – spencer.sm May 02 '18 at 23:12
  • 2
    @pr1001 The OP specifically asked: "How do I round this down to, say, 1.543 when I *print* totalWorkTimeInHours?" So, the OP is talking about how to display the number, so a `String` solution is perfectly legitimate. – Zonker.in.Geneva Oct 24 '18 at 12:52
  • Well such things happen to me when I already knew solution to a problem but I use stackoverflow..Anyway thanks for reminding me! :) – Amber K Nov 23 '18 at 08:38
  • You could always convert to the String value using this method, and then convert the new String with the number of decimal places you want back to a double. – D. Pratt Mar 26 '19 at 14:12
375

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")
Maxim Pavlov
  • 2,962
  • 1
  • 23
  • 33
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
  • 3
    Great answer. I might suggest on #5 that you might consider using `Decimal`, which is toll free bridged to `NSDecimalNumber`. `Decimal` is Swift’s native type and offers more elegant support for native operators like `+`, `-`, etc. – Rob Feb 05 '18 at 17:40
  • @Rob I've updated my answer with `NSDecimalRound(_:_:_:_:)` function. Thanks. – Imanou Petit Feb 07 '18 at 18:13
  • 1
    Using #9 choice will guarantee that you will expect the fixed fraction (number of precision digits), lets say decimal number 43.12345 and fraction = 6, you get 43.123450 – Almas Adilbek Apr 20 '18 at 17:11
  • 1
    @ImanouPetit Thank you for posting this. I can nuke a couple of extensions. – Adrian Jun 03 '18 at 00:35
  • 6
    I am sad `NumberFormatter` is the last option while it should be the first for presenting numbers to users. No other method generates properly localized numbers. – Sulthan Jan 20 '19 at 14:43
  • What's the code, if I have 0.00639542871 to DETECT FIRST NUMBER AFTER ZEROS and makes it +1 so the output to be 0.007 – Bogdan Bogdanov Oct 09 '19 at 15:39
  • This works ONLY if you cast result explicitly into float: let roundedValue1 = Float((0.6856 * 100).rounded(.up) / 100) – Hadži Lazar Pešić Mar 06 '20 at 15:04
  • 1
    The extremely customizable nature of NumberFormatter did it for me! Glad I read all the way to the bottom of your answer. – Carl Smith Apr 09 '21 at 09:26
203

In Swift 5.5 and Xcode 13.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
Claudio Silva
  • 3,743
  • 1
  • 26
  • 27
  • Looking at your code I made a small like this and it works fine: extension Float { var toString: String { return String(format: "%.2f", self) } } – Sanjeevcn Apr 18 '22 at 06:50
  • I used it on a string var that goes on a long string expression to be displayed on SwiftUI Text view. Lot of thanks – Fortran programmer Oct 28 '22 at 00:27
61

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

Krunal Patel
  • 1,649
  • 1
  • 14
  • 22
35

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
Joannes
  • 2,569
  • 3
  • 17
  • 39
Ash
  • 9,064
  • 3
  • 48
  • 59
31

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
pkamb
  • 33,281
  • 23
  • 160
  • 191
jaiswal Rajan
  • 4,641
  • 1
  • 27
  • 16
26

Swift 4, Xcode 10

yourLabel.text =  String(format:"%.2f", yourDecimalValue)
Naishta
  • 11,885
  • 4
  • 72
  • 54
  • 1
    I didn't downvote, but I think the reason might be because this is returning a string representation of a number, not the number. Which is fine if that's all you need but you might want the number itself rounded off for further use. The OP did say "when I print" so I do think this is an acceptable, easy, and clean solution in this case. – Ben Stahl Feb 19 '19 at 21:07
  • 1
    Perfect. One line solution. I just needed to show decimal values as Strings in my labels. – zeeshan Mar 06 '19 at 19:40
19

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))

Merichle
  • 693
  • 11
  • 15
17

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

Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
George Filippakos
  • 16,359
  • 15
  • 81
  • 92
16

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 = 427.3000000002
let value = foo.roundedDecimal(to: 2) // results in 427.30

And 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

if let string = formatter.string(for: value) {
    print(string)
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 3
    The best answer so far. – Codetard Sep 23 '18 at 11:29
  • `(4.81).roundedDecimal(to: 2, mode: .down)` will return 4.8 instead of 4.81, use `Decimal(string: self.description)!` for a precise `decimalValue` – vk.edward.li Nov 22 '18 at 20:16
  • 2
    @vk.edward.li - Yes, one should be wary about rounding decimals up/down, because values like 4.81 simply can not be accurately represented with `Double` (it becomes `4.8099999999999996`). But I'd advise against using `description` (as the rounding it employs is not documented and is subject to change). If you really want to be doing decimal-accurate math, you should avoid `Double` entirely and should instead use `Decimal` directly (e.g. `Decimal(sign: .plus, exponent: -2, significand: 481)` or `Decimal(string: "4.81")`. But don't use `description`. – Rob Nov 26 '18 at 01:08
  • @Rob usually it is impossible to get the string value of "4.81" if it is stored as Double, so you have to use self.description (a modified Grisu2 algorithm) to fix the precision which is already lost – vk.edward.li Dec 10 '18 at 11:54
  • 1
    I understand your point. I just disagree with your solution. The rounding behavior of `description` method is neither documented nor guaranteed. Plus, it’s not localized. IMHO, it’s a mistake to use `description` for anything other than logging purposes. I’d either use `Decimal` throughout, avoiding using `Double` entirely, or just use a different rounding mode. Or, if you must, use your own localized method that uses Grisu-style algorithm (but that seems unnecessary when you know to how many decimal places you want to round). But I’d avoid relying on this ancillary behavior of `description`. – Rob Dec 12 '18 at 16:16
13

A handy way can be the use of extension of type Double

extension Double {
    var roundTo2f: Double {return Double(round(100 *self)/100)  }
    var roundTo3f: Double {return Double(round(1000*self)/1000) }
}

Usage:

let regularPie:  Double = 3.14159
var smallerPie:  Double = regularPie.roundTo3f  // results 3.142
var smallestPie: Double = regularPie.roundTo2f  // results 3.14
Marco Leong
  • 565
  • 4
  • 11
12

This is a sort of a long workaround, which may come in handy if your needs are a little more complex. You can use a number formatter in Swift.

let numberFormatter: NSNumberFormatter = {
    let nf = NSNumberFormatter()
    nf.numberStyle = .DecimalStyle
    nf.minimumFractionDigits = 0
    nf.maximumFractionDigits = 1
    return nf
}()

Suppose your variable you want to print is

var printVar = 3.567

This will make sure it is returned in the desired format:

numberFormatter.StringFromNumber(printVar)

The result here will thus be "3.6" (rounded). While this is not the most economic solution, I give it because the OP mentioned printing (in which case a String is not undesirable), and because this class allows for multiple parameters to be set.

Inkidu616
  • 389
  • 3
  • 17
  • 1
    A quick note that any formatter is rather expensive programmatically, making it ill-advised for tasks that need to be performed quickly or repetitively. – Jonathan Thornton Aug 07 '17 at 20:13
10

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
          }
      }
      
staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
8

I would use

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

and change .3f to any number of decimal numbers you need

8

This is more flexible algorithm of rounding to N significant digits

Swift 3 solution

extension Double {
// Rounds the double to 'places' significant digits
  func roundTo(places:Int) -> Double {
    guard self != 0.0 else {
        return 0
    }
    let divisor = pow(10.0, Double(places) - ceil(log10(fabs(self))))
    return (self * divisor).rounded() / divisor
  }
}


// Double(0.123456789).roundTo(places: 2) = 0.12
// Double(1.23456789).roundTo(places: 2) = 1.2
// Double(1234.56789).roundTo(places: 2) = 1200
Nikita Ivaniushchenko
  • 1,425
  • 11
  • 11
8

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
Uma Madhavi
  • 4,851
  • 5
  • 38
  • 73
Ayman Badr
  • 81
  • 1
  • 5
8

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!

Cable W
  • 633
  • 1
  • 8
  • 17
7

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
Abuzar Manzoor
  • 379
  • 4
  • 13
6

Not Swift but I'm sure you get the idea.

pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
yogi
  • 144
  • 3
6

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)
Lukasz D
  • 241
  • 4
  • 8
5

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))
    }

}
Matiu Awaiti
  • 51
  • 1
  • 2
4

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

4
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..

Amais Sheikh
  • 421
  • 5
  • 12
4

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
Pratik Sodha
  • 3,679
  • 2
  • 19
  • 38
3

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))))
vadian
  • 274,689
  • 30
  • 353
  • 361
2

I found this wondering if it is possible to correct a user's input. That is if they enter three decimals instead of two for a dollar amount. Say 1.111 instead of 1.11 can you fix it by rounding? The answer for many reasons is no! With money anything over i.e. 0.001 would eventually cause problems in a real checkbook.

Here is a function to check the users input for too many values after the period. But which will allow 1., 1.1 and 1.11.

It is assumed that the value has already been checked for successful conversion from a String to a Double.

//func need to be where transactionAmount.text is in scope

func checkDoublesForOnlyTwoDecimalsOrLess()->Bool{


    var theTransactionCharacterMinusThree: Character = "A"
    var theTransactionCharacterMinusTwo: Character = "A"
    var theTransactionCharacterMinusOne: Character = "A"

    var result = false

    var periodCharacter:Character = "."


    var myCopyString = transactionAmount.text!

    if myCopyString.containsString(".") {

         if( myCopyString.characters.count >= 3){
                        theTransactionCharacterMinusThree = myCopyString[myCopyString.endIndex.advancedBy(-3)]
         }

        if( myCopyString.characters.count >= 2){
            theTransactionCharacterMinusTwo = myCopyString[myCopyString.endIndex.advancedBy(-2)]
        }

        if( myCopyString.characters.count > 1){
            theTransactionCharacterMinusOne = myCopyString[myCopyString.endIndex.advancedBy(-1)]
        }


          if  theTransactionCharacterMinusThree  == periodCharacter {

                            result = true
          }


        if theTransactionCharacterMinusTwo == periodCharacter {

            result = true
        }



        if theTransactionCharacterMinusOne == periodCharacter {

            result = true
        }

    }else {

        //if there is no period and it is a valid double it is good          
        result = true

    }

    return result


}
Pang
  • 9,564
  • 146
  • 81
  • 122
Mountain Man
  • 252
  • 2
  • 10
2

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
  • This one is neat implementation of representing it as a String. I wonder if it is possible or rational to write an extension of number of digits representation after period still maintaining it as Double. – thinkswift Jul 16 '19 at 18:24
2

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))
    }
}
OwlOCR
  • 1,127
  • 11
  • 22
1
//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"
Pang
  • 9,564
  • 146
  • 81
  • 122
Davender Verma
  • 503
  • 2
  • 12
1

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
Jeri P.M
  • 399
  • 5
  • 15
1

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.

Nathan Day
  • 5,981
  • 2
  • 24
  • 40
1

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
vedrano
  • 2,961
  • 1
  • 28
  • 25
1

Swift 4 Best Way

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

let val = round(100 * scale) / 100
Kingsley Mitchell
  • 2,412
  • 2
  • 18
  • 25