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
?
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
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
}
}
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
Comment est-ce que j'arrondis à 1.543 quand j'imprime
totalWorkTimeInHours
?
Pour arrondir totalWorkTimeInHours
à 3 chiffres pour l’impression, utilisez le constructeur String
qui utilise une chaîne format
:
print(String(format: "%.3f", totalWorkTimeInHours))
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
.
FloatingPoint
rounded()
Dans le cas le plus simple, vous pouvez utiliser la méthode Double
round()
.
let roundedValue1 = (0.6844 * 1000).rounded() / 1000
let roundedValue2 = (0.6849 * 1000).rounded() / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
FloatingPoint
rounded(_:)
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
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
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
NSDecimalNumber
rounding(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
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
NSString
init(format:arguments:)
initializerSi 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
String
init(format:_:)
initializerLe 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
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")
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
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))
Swift 4, Xcode 1
yourLabel.text = String(format:"%.2f", yourDecimalValue)
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
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
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
Soit:
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))!
}
}
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
}
}
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.
J'utiliserais
print(String(format: "%.3f", totalWorkTimeInHours))
et changez .3f en un nombre quelconque de nombres décimaux dont vous avez besoin
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
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)
}
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
Pas Swift mais je suis sûr que vous avez compris l'idée.
pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
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
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"
extension String{
var roundedValue:String {
return String(format: "%.3f", self)
}}
Utilisation:
totalWorkTimeInHours.roundedValue
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
}
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))
}
}