web-dev-qa-db-fra.com

Arrondir une double valeur à x nombre de décimales dans swift

Quelqu'un peut-il me dire comment arrondir une valeur double au nombre x décimales dans Swift?

J'ai:

var totalWorkTimeInHours = (totalWorkTime/60/60)

Avec totalWorkTime étant un NSTimeInterval (double) en seconde.

totalWorkTimeInHours me donnera les heures, mais il me donne la quantité de temps dans un nombre aussi long et précis, par exemple. 1.543240952039 ......

Comment puis-je arrondir ce chiffre à 1,543 lorsque j'imprime totalWorkTimeInHours?

340
Leighton

Vous pouvez utiliser la fonction round de Swift pour accomplir cela.

Pour arrondir une Double avec une précision de 3 chiffres, multipliez-la d'abord par 1000, arrondissez-la et divisez le résultat arrondi par 1000:

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

Hormis tout type de solution printf(...) ou String(format: ...), le résultat de cette opération est toujours de type Double.

EDIT:
En ce qui concerne les commentaires indiquant que cela ne fonctionne parfois pas, veuillez lire ceci:

Ce que tout informaticien devrait savoir sur l'arithmétique en virgule flottante

342
zisoft

Extension pour Swift 2

Une solution plus générale est l'extension suivante, qui fonctionne avec 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 pour Swift 3

Dans Swift 3 round est remplacé par 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
    }
}


Exemple qui renvoie Double arrondi à 4 décimales:

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
396
Sebastian

Comment est-ce que j'arrondis à 1.543 quand j'imprimetotalWorkTimeInHours?

Pour arrondir totalWorkTimeInHours à 3 chiffres pour l’impression, utilisez le constructeur String qui utilise une chaîne format:

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

Avec Swift 5, en fonction de vos besoins, vous pouvez choisir l’un des 9 styles suivants pour obtenir un résultat arrondi à partir de Double.


#1. Utilisation de la méthode FloatingPointrounded()

Dans le cas le plus simple, vous pouvez utiliser la méthode Doubleround().

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. Utilisation de la méthode FloatingPointrounded(_:)

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. Utilisation de la fonction Darwin round

Foundation propose une fonction round 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. Utilisation d'une méthode personnalisée d'extension Double générée avec les fonctions Darwin round et pow

Si vous souhaitez répéter plusieurs fois l'opération précédente, il peut être judicieux de refactoriser votre code.

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. Utilisation de la méthode NSDecimalNumberrounding(accordingToBehavior:)

Si nécessaire, NSDecimalNumber offre une solution détaillée mais puissante pour arrondir les nombres décimaux.

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. Utiliser la fonction NSDecimalRound(_:_:_:_:)

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

#sept. Utilisation de NSStringinit(format:arguments:) initializer

Si vous souhaitez renvoyer un NSString à partir de votre opération d'arrondi, l'utilisation de l'initialisateur NSString est une solution simple mais efficace.

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. Utilisation de Stringinit(format:_:) initializer

Le type String de Swift est relié à la classe NSString de Foundation. Par conséquent, vous pouvez utiliser le code suivant afin de renvoyer un String à partir de votre opération d'arrondi:

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. Utilisation de NumberFormatter

Si vous souhaitez obtenir un String? de votre opération d'arrondi, NumberFormatter offre une solution hautement personnalisable.

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")
205
Imanou Petit

Dans Swift 2.0 et Xcode 7.2:

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

Exemple:

enter image description here

90
Claudio Guirunas

S'appuyant sur la réponse de Yogi, voici une fonction Swift qui fait le travail:

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

C'est un code entièrement travaillé

Swift 3.0/4.0, Xcode 9.0 GM/9.2

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

sortie - 123

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

sortie - 123.3

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

sortie - 123.33

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

sortie - 123.326

18
Krunal Patel

Le code pour les chiffres spécifiques après les décimales est:

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

Ici, le% .3f indique au Swift de faire en sorte que ce nombre soit arrondi à 3 décimales. Si vous voulez un nombre double, vous pouvez utiliser ce code:

// Chaîne à doubler

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

17
Ramazan Karami

Swift 4, Xcode 1

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

Dans Swift 3.0 et Xcode 8.0:

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

Utilisez cette extension comme ça,

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

tilisez la bibliothèque Foundation Darwin intégrée

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

Sorties: 12.988

13
George Filippakos

Un moyen pratique peut être d'utiliser extension de 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
9
Marco Leong

Soit:

  1. Utiliser String(format:):

    • Conversion de type Double à String avec le spécificateur de format %.3f, puis retour à Double

      Double(String(format: "%.3f", 10.123546789))!
      
    • Ou étendre Double pour gérer les positions décimales:

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

    • multiplier par 10 ^ 3, arrondir et diviser par 10 ^ 3 ...

      (1000 * 10.123546789).rounded()/1000
      
    • Ou étendre Double pour gérer les positions décimales:

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

C'est une sorte de solution de contournement longue qui peut s'avérer utile si vos besoins sont un peu plus complexes. Vous pouvez utiliser un formateur de nombres dans Swift.

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

Supposons que la variable que vous voulez imprimer soit

var printVar = 3.567

Cela garantira qu'il est renvoyé au format souhaité:

numberFormatter.StringFromNumber(printVar)

Le résultat ici sera donc "3.6" (arrondi). Bien que ce ne soit pas la solution la plus économique, je la donne parce que l’OP mentionne l’impression (auquel cas une chaîne n’est pas indésirable) et que cette classe permet de définir plusieurs paramètres.

7
Inkidu616

J'utiliserais

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

et changez .3f en un nombre quelconque de nombres décimaux dont vous avez besoin

7

Ceci est un algorithme plus flexible pour arrondir à N chiffres significatifs

solution Swift

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
6

Si vous voulez arrondir les valeurs Double, vous pouvez utiliser Swift Decimal pour ne pas introduire d'erreur susceptible de se produire lorsque vous essayez de calculer avec ces valeurs arrondies. Si vous utilisez Decimal, il peut représenter avec précision les valeurs décimales de cette valeur à virgule flottante arrondie.

Alors tu peux faire:

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

Ensuite, vous pouvez obtenir la valeur arrondie Decimal comme ceci:

let foo = 427.3000000002
let value = foo.roundedDecimal(to: 2) // results in 427.30

Et si vous souhaitez l'afficher avec un nombre spécifié de décimales (ainsi que localiser la chaîne pour les paramètres régionaux actuels de l'utilisateur), vous pouvez utiliser un paramètre NumberFormatter:

let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2

if let string = formatter.string(for: value) {
    print(string)
}
6
Rob

Le meilleur moyen de formater une propriété double consiste à utiliser les méthodes prédéfinies Apple.

mutating func round(_ rule: FloatingPointRoundingRule)

FloatingPointRoundingRule est une énumération qui a les possibilités suivantes

Cas d'énumération:

case awayFromZero Arrondissez à la valeur autorisée la plus proche dont la magnitude est supérieure ou égale à celle de la source.

case down Arrondit à la valeur autorisée la plus proche, inférieure ou égale à la source.

case toNearestOrAwayFromZero Arrondir à la valeur autorisée la plus proche; si deux valeurs sont également proches, on choisit celle de plus grande magnitude.

case toNearestOrEven Arrondir à la valeur autorisée la plus proche; si deux valeurs sont également proches, le même est choisi.

cas vers zéro Arrondit à la valeur autorisée la plus proche dont la magnitude est inférieure ou égale à celle de la source.

casse vers le haut Arrondit à la valeur autorisée la plus proche, supérieure ou égale à la source.

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

Pas Swift mais je suis sûr que vous avez compris l'idée.

pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
5
yogi

autour d'une double valeur à x nombre de décimales
NON. de chiffres après la virgule

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
5
Ayman Badr

Vous pouvez ajouter cette extension:

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

et appelez ça comme ça:

let ex: Double = 10.123546789
print(ex.clean) // 10.12
//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"
1
Davender Verma Soni
extension String{
  var roundedValue:String {
     return String(format: "%.3f", self)
}}

Utilisation:

totalWorkTimeInHours.roundedValue
1
Bhargav Sejpal

J'ai trouvé cela en me demandant s'il est possible de corriger la saisie d'un utilisateur. C’est-à-dire s’ils saisissent trois décimales au lieu de deux pour un montant en dollars. Dites 1.111 au lieu de 1.11, pouvez-vous résoudre le problème en arrondissant? La réponse pour de nombreuses raisons est non! Avec de l’argent, quoi que ce soit, c’est-à-dire que 0,001 causerait éventuellement des problèmes dans un vrai chéquier.

Voici une fonction pour vérifier les entrées des utilisateurs pour trop de valeurs après la période. Mais ce qui permettra 1., 1.1 et 1.11.

Il est supposé que la valeur a déjà été vérifiée pour une conversion réussie d'une chaîne en un 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


}
1
Mountain Man

Cela semble fonctionner dans Swift 5.

Assez surpris qu'il n'y ait pas déjà de fonction standard pour cela.

// Troncature des positions doubles à n-décimales avec arrondi

extension Double {

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

}
0
Matiu Awaiti