ios - Redondeando un valor doble a x número de decimales en swift
double nstimeinterval (27)
¿Cómo redondeo esto a, digamos, 1.543 cuando imprimo
totalWorkTimeInHours
?
Para redondear
totalWorkTimeInHours
a 3 dígitos para imprimir, use el constructor de
String
que toma una cadena de
format
:
print(String(format: "%.3f", totalWorkTimeInHours))
¿Alguien puede decirme cómo redondear un valor doble a x número de decimales en Swift?
Yo tengo:
var totalWorkTimeInHours = (totalWorkTime/60/60)
Con
totalWorkTime
siendo un NSTimeInterval (doble) en segundo.
totalWorkTimeInHours
me dará las horas, pero me da la cantidad de tiempo en un número tan largo y preciso, por ejemplo, 1.543240952039 ......
¿Cómo redondeo esto a, digamos, 1.543 cuando imprimo
totalWorkTimeInHours
?
Extensión para Swift 2
Una solución más general es la siguiente extensión, que funciona con Swift 2 y 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
}
}
Extensión para Swift 3
En Swift 3, la
round
se reemplaza por
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
}
}
Ejemplo que devuelve Doble redondeado a 4 decimales:
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
Aquí hay uno para SwiftUI si necesita un elemento de texto con el valor numérico.
struct RoundedDigitText : View { let digits : Int let number : Double var body : some View { Text(String(format: "%./(digits)f", number)) } }
Basándose en la respuesta de Yogi, aquí hay una función Swift que hace el trabajo:
func roundToPlaces(value:Double, places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return round(value * divisor) / divisor
}
Con Swift 5, según sus necesidades, puede elegir uno de los
9 estilos siguientes
para obtener un resultado redondeado de un
Double
.
# 1
Usando el método
FloatingPoint
rounded()
En el caso más simple, puede usar el método
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
# 2
Uso del método
rounded(_:)
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
# 3
Usando la función
round
Darwin
Foundation ofrece una función
round
través de 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.
Usando un método personalizado de
Double
extensión creado con las funciones de
pow
y
pow
Si desea repetir la operación anterior muchas veces, refactorizar su código puede ser una buena 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.
Uso del
NSDecimalNumber
rounding(accordingToBehavior:)
NSDecimalNumber
rounding(accordingToBehavior:)
método
rounding(accordingToBehavior:)
Si es necesario,
NSDecimalNumber
ofrece una solución detallada pero poderosa para redondear números decimales.
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.
Uso de la función
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
# 7.
Usando
NSString
init(format:arguments:)
inicializador
Si desea devolver un
NSString
de su operación de redondeo, usar el inicializador
NSString
es una solución simple pero eficiente.
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.
Usando
String
init(format:_:)
inicializador
El tipo de
String
de Swift se
NSString
clase
NSString
de
NSString
.
Por lo tanto, puede usar el siguiente código para devolver una
String
de su operación de redondeo:
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.
Usando
NumberFormatter
Si espera obtener una
String?
desde su operación de redondeo,
NumberFormatter
ofrece una solución altamente personalizable.
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")
El código para dígitos específicos después de decimales es:
var a = 1.543240952039
var roundedString = String(format: "%.3f", a)
Aquí, el% .3f le dice a Swift que redondee este número a 3 decimales. Y si desea un número doble, puede usar este código:
// String to Double
var roundedString = Double(String(format: "%.3f", b))
Encontré esto preguntándome si es posible corregir la entrada de un usuario. Es decir, si ingresan tres decimales en lugar de dos por un monto en dólares. Digamos 1.111 en lugar de 1.11, ¿puedes arreglarlo redondeando? ¡La respuesta por muchas razones es no! Con dinero por encima de 0.001 eventualmente causaría problemas en una chequera real.
Aquí hay una función para verificar la entrada de los usuarios para demasiados valores después del período. Pero lo que permitirá 1., 1.1 y 1.11.
Se supone que el valor ya se ha verificado para una conversión exitosa de una Cadena a una Doble.
//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"
Esta es una especie de solución temporal larga, que puede ser útil si sus necesidades son un poco más complejas. Puede usar un formateador de números en Swift.
let numberFormatter: NSNumberFormatter = {
let nf = NSNumberFormatter()
nf.numberStyle = .DecimalStyle
nf.minimumFractionDigits = 0
nf.maximumFractionDigits = 1
return nf
}()
Suponga que su variable que desea imprimir es
var printVar = 3.567
Esto asegurará que se devuelva en el formato deseado:
numberFormatter.StringFromNumber(printVar)
El resultado aquí será "3.6" (redondeado). Si bien esta no es la solución más económica, la doy porque el OP mencionó la impresión (en cuyo caso, una Cadena no es indeseable), y porque esta clase permite establecer múltiples parámetros.
Este es un algoritmo más flexible de redondeo a N dígitos significativos
Solución 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
Este es un código completamente trabajado
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)
salida - 123
self.lblValue_1.text = String(format:"%.1f", doubleValue)
print(self.lblValue_1.text)
salida - 123.3
self.lblValue_2.text = String(format:"%.2f", doubleValue)
print(self.lblValue_2.text)
salida - 123.33
self.lblValue_3.text = String(format:"%.3f", doubleValue)
print(self.lblValue_3.text)
salida - 123.326
Esto parece funcionar en Swift 5.
Bastante sorprendido ya no hay una función estándar para esto.
// Truncamiento de dobles a n-decimales con redondeo
extension Double {
var clean: String {
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(format: "%.2f", self)
}
}
La mejor manera de formatear una propiedad doble es utilizar los métodos predefinidos de Apple.
mutating func round(_ rule: FloatingPointRoundingRule)
FloatingPointRoundingRule es una enumeración que tiene las siguientes posibilidades
Casos de enumeración:
case awayFromZero Redondea al valor permitido más cercano cuya magnitud es mayor o igual que la de la fuente.
caso abajo Redondear al valor permitido más cercano que sea menor o igual que la fuente.
case toNearestOrAwayFromZero Round al valor permitido más cercano; Si dos valores son igualmente cercanos, se elige el de mayor magnitud.
case toNearestOrEven Round al valor permitido más cercano; Si dos valores son igualmente cercanos, se elige el par.
caso hacia cero Redondea al valor permitido más cercano cuya magnitud es menor o igual que la de la fuente.
caso arriba Redondea al valor permitido más cercano que sea mayor o igual que la fuente.
var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0
No Swift, pero estoy seguro de que tienes la idea.
var x = 1.5657676754
var y = (x*10).rounded()/10
print(y) // 1.6
Para evitar imperfecciones de flotación, 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 se redondea a 1075.57 cuando se usa Float con escala: 2 y .down
1075.58 se redondea a 1075.58 cuando se usa Decimal con escala: 2 y .down
Puede usar la función
round
de Swift para lograr esto.
Para redondear un
Double
con precisión de 3 dígitos, primero multiplíquelo por 1000, redondee y divida el resultado redondeado por 1000:
let x = 1.23556789
let y = Double(round(1000*x)/1000)
print(y) // 1.236
Además de cualquier tipo de soluciones
printf(...)
o
String(format: ...)
, el resultado de esta operación sigue siendo del tipo
Double
.
EDITAR:
En cuanto a los comentarios de que a veces no funciona, lea esto:
Lo que todo informático debe saber sobre la aritmética de coma flotante
Puedes agregar esta extensión:
let ex: Double = 10.123546789
print(ex.clean) // 10.12
y llámalo así:
//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
}
Si desea redondear valores
Double
, es posible que desee utilizar Swift
Decimal
para no introducir ningún error que pueda surgir cuando intente matemática con estos valores redondeados.
Si usa
Decimal
, puede representar con precisión los valores decimales de ese valor de punto flotante redondeado.
Entonces puedes hacer:
pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
Luego, puede obtener el valor
Decimal
redondeado de la siguiente manera:
var x = 1.5657676754
var y = (x*10000).rounded()/10000
print(y) // 1.5658
Y si desea mostrarlo con un número específico de lugares decimales (así como localizar la cadena para la configuración regional actual del usuario), puede usar un
NumberFormatter
:
var x = 1.5657676754
var y = (x*100).rounded()/100
print(y) // 1.57
Una manera práctica puede ser el uso de la extensión de tipo Doble
extension Double {
var roundTo2f: Double {return Double(round(100 *self)/100) }
var roundTo3f: Double {return Double(round(1000*self)/1000) }
}
Uso:
let regularPie: Double = 3.14159
var smallerPie: Double = regularPie.roundTo3f // results 3.142
var smallestPie: Double = regularPie.roundTo2f // results 3.14
Ya sea:
-
Usando
String(format:)
:-
Typecast
Double
toString
con el especificador de formato%.3f
y luego nuevamente aDouble
Double(String(format: "%.3f", 10.123546789))!
-
O extienda
Double
para manejar lugares N-Decimales:extension Double { func rounded(toDecimalPlaces n: Int) -> Double { return Double(String(format: "%./(n)f", self))! } }
-
-
Por cálculo
-
multiplica con 10 ^ 3, redondea y luego divide por 10 ^ 3 ...
(1000 * 10.123546789).rounded()/1000
-
O extienda
Double
para manejar lugares N-Decimales:extension Double { func rounded(toDecimalPlaces n: Int) -> Double { let multiplier = pow(10, Double(n)) return (multiplier * self).rounded()/multiplier } }
-
yo usaría
print(String(format: "%.3f", totalWorkTimeInHours))
y cambie .3f a cualquier número de números decimales que necesite
En Swift 3.0 y Xcode 8.0:
yourLabel.text = String(format:"%.2f", yourDecimalValue)
Use esta extensión así,
extension Double {
func roundTo(places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}
Swift 4, Xcode 10
let doubleValue = 3.567
let roundedValue = doubleValue.roundTo(places: 2)
print(roundedValue) // prints 3.56
Utilice la biblioteca integrada de Foundation Darwin
SWIFT 3
extension Double {
func round(to places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return Darwin.round(self * divisor) / divisor
}
}
Uso:
let number:Double = 12.987654321
print(number.round(to: 3))
Salidas: 12.988
redondea un valor doble a x número de decimales
NO.
de dígitos después del decimal
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
}
}
let foo = 427.3000000002
let value = foo.roundedDecimal(to: 2) // results in 427.30
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
if let string = formatter.string(for: value) {
print(string)
}
extension String{
var roundedValue:String {
return String(format: "%.3f", self)
}}
totalWorkTimeInHours.roundedValue
Uso:
extension Double {
func truncate(to places: Int) -> Double {
return Double(Int((pow(10, Double(places)) * self).rounded())) / pow(10, Double(places))
}
}