Arrondir une valeur double à x nombre de décimales dans swift
Quelqu'un peut-il me dire comment arrondir une double valeur à x nombre de décimales dans Swift?
J'ai:
var totalWorkTimeInHours = (totalWorkTime/60/60)
Avec {[1] } étant un NSTimeInterval (double) en second.
totalWorkTimeInHours
me donnera les heures, mais il me donne la quantité de temps dans un nombre aussi long précis, par exemple 1.543240952039......
Comment arrondir ceci à, disons, 1.543 quand j'imprime totalWorkTimeInHours
?
21 réponses
Vous pouvez utiliser la fonction round
de Swift pour y parvenir.
Pour arrondir un Double
avec une précision de 3 chiffres, multipliez-le d'abord par 1000, arrondissez-le et divisez le résultat arrondi par 1000:
let x = 1.23556789
let y = Double(round(1000*x)/1000)
print(y) // 1.236
Autre que tout type de solutions printf(...)
ou String(format: ...)
, le résultat de cette opération est toujours de type Double
.
Modifier:
En ce qui concerne les commentaires que cela ne fonctionne parfois pas, veuillez lire ceci:
Ce Que Tout Informaticien Devrait Savoir Arithmétique À Virgule Flottante
Extension pour Swift 2
Une solution plus générale est l'extension suivante, qui fonctionne avec Swift 2 et 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
Utilisez le constructeur String
qui prend une chaîne format
:
print(String(format: "%.3f", totalWorkTimeInHours))
Avec Swift 4, en fonction de vos besoins, vous pouvez choisir l'un des 9 styles suivants, afin d'avoir un résultat arrondi à partir d'un Double
.
#1. À l'aide de FloatingPoint
rounded()
méthode
Dans le cas le plus simple, vous pouvez utiliser Double
round()
méthode.
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. À l'aide de FloatingPoint
rounded(_:)
méthode
var roundedValue1 = (0.6844 * 1000).rounded(.toNearestOrEven) / 1000
var roundedValue2 = (0.6849 * 1000).rounded(.toNearestOrEven) / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
#3. Utilisation de la fonction Darwin round
Fondation offre 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
construite avec les fonctions Darwin round
et pow
Si vous voulez répéter l'opération précédente plusieurs fois, refactoriser votre code peut être une bonne idée.
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. À l'aide de NSDecimalNumber
rounding(accordingToBehavior:)
méthode
Si nécessaire, NSDecimalNumber
offre une solution verbeuse 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. À l'aide de NSDecimalRound(_:_:_:_:)
fonction
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. À l'aide de NSString
init(format:arguments:)
initialiseur
Si vous voulez renvoyer un NSString
de votre opération d'arrondi, l'utilisation de l'initialiseur 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. À l'aide de String
init(format:_:)
initialiseur
Le type String
de Swift est relié à la classe NSString
de Foundation (vous pouvez en apprendre plus à ce sujet en lisant le langage de programmation Swift). Par conséquent, vous pouvez utiliser le code suivant dans pour renvoyer un String
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. À l'aide de NumberFormatter
Si vous prévoyez d'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")
En 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
}
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
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 ceci,
let doubleValue = 3.567
let roundedValue = doubleValue.roundTo(places: 2)
print(roundedValue) // prints 3.56
Le code pour les chiffres spécifiques après les décimales est:
var a = 1.543240952039
var roundedString = String(format: "%.3f", a)
Voici le %.3f indique au swift de faire arrondir ce nombre à 3 décimales.et si vous voulez doubler le nombre, vous pouvez utiliser ce code:
/ / Chaîne Pour Doubler
var roundedString = Double(String(format: "%.3f", b))
Une façon pratique peut être l'utilisation de extension de type Double
extension Double {
var roundTo2f: Double {return Double(round(100 *self)/100) }
var roundTo3f: Double {return Double(round(1000*self)/1000) }
}
Utilisation:
let regularPie: Double = 3.14159
var smallerPie: Double = regularPie.roundTo3f // results 3.142
var smallestPie: Double = regularPie.roundTo2f // results 3.14
Utilisez la bibliothèque Darwin de fondation 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
}
}
Utilisation:
let number:Double = 12.987654321
print(number.round(to: 3))
Sorties: 12.988
C'est une sorte de solution de contournement longue, qui peut être 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 votre variable que vous voulez imprimer soit
var printVar = 3.567
Cela permettra de s'assurer qu'il est retourné dans le 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 le donne parce que L'OP a mentionné l'impression (auquel cas une chaîne n'est pas indésirable), et parce que cette classe permet de définir plusieurs paramètres.
Je voudrais utiliser
print(String(format: "%.3f", totalWorkTimeInHours))
Et changer .3f à n'importe quel nombre de nombres décimaux dont vous avez besoin
Pas rapide mais je suis sûr que vous avez l'idée.
pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
C'est un algorithme plus flexible d'arrondi à n chiffres significatifs
Solution Swift 3
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
Arrondir une valeur double à X nombre de décimales
AUCUN. de chiffres après décimal
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
La meilleure façon de formater une propriété double est d'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:
Cas awayFromZero Arrondir à la valeur autorisée la plus proche dont la magnitude est supérieure ou égale à celle de la source.
Cas vers le bas Tour à la plus proche valeur autorisée est inférieure ou égale à la source.
Affaire toNearestOrAwayFromZero Arrondir à la valeur autorisée la plus proche; si deux valeurs sont également proches, celle avec la plus grande magnitude est choisie.
Cas toNearestOrEven Arrondir à la valeur autorisée la plus proche; si deux valeurs sont également proches, la valeur paire est choisie.
Cas verszero Tour à la plus proche valeur autorisée dont la magnitude est inférieure ou égale à celle de la source.
Cas vers le haut Arrondir à la valeur autorisée la plus proche qui est supérieure à ou égal à la source.
var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0
Soit:
-
En utilisant
String(format:)
:-
Transtypage
Double
àString
avec%.3f
spécificateur de format et ensuite de retour àDouble
Double(String(format: "%.3f", 10.123546789))!
-
Ou étendre
Double
pour gérer N décimales:extension Double { func rounded(toDecimalPlaces n: Int) -> Double { return Double(String(format: "%.\(n)f", self))! } }
-
-
Par calcul
-
Multiplier par 10^3, arrondir puis diviser par 10^3...
(1000 * 10.123546789).rounded()/1000
-
Ou étendre
Double
pour gérer N-décimal lieux:extension Double { func rounded(toDecimalPlaces n: Int) -> Double { let multiplier = pow(10, Double(n)) return (multiplier * self).rounded()/multiplier } }
-
Si vous voulez arrondir les valeurs Double
, vous pouvez utiliser Swift Decimal
afin de ne pas introduire d'erreurs qui peuvent apparaître 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.
Donc vous pouvez 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 Decimal
arrondie comme suit:
let foo = 427.3000000002
let value = foo.roundedDecimal(to: 2) // results in 427.30
Et si vous voulez l'afficher avec un nombre spécifié de décimales (ainsi que localiser la chaîne pour le paramètres régionaux actuels de l'utilisateur), vous pouvez utiliser un NumberFormatter
:
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
if let string = formatter.string(for: value) {
print(string)
}
J'ai trouvé cela se demandant s'il est possible de corriger l'entrée d'un utilisateur. C'est-à-dire s'ils entrent trois décimales au lieu de deux pour un montant en dollars. Dites 1.111 au lieu de 1.11 pouvez-vous le réparer en arrondissant? La réponse pour de nombreuses raisons est non! Avec de l'argent, quelque chose de plus, c'est-à-dire 0.001 finirait par causer des problèmes dans un vrai chéquier.
Voici une fonction pour vérifier l'entrée des utilisateurs pour trop de valeurs après la période. Mais qui permettra 1., 1.1 et 1.11.
On suppose que le la valeur a déjà été vérifiée pour la conversion réussie d'une chaîne en 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
}
//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"