Redondeando un valor doble a x número de decimales en swift


¿Puede alguien decirme cómo redondear un valor doble a x número de decimales en Swift?

Tengo:

var totalWorkTimeInHours = (totalWorkTime/60/60)

Siendo totalWorkTime un NSTimeInterval (doble) en segundo lugar.

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?

Author: Tot Zam, 2014-12-07

21 answers

Puede usar la función round de Swift para lograr esto.

Para redondear a Double con precisión de 3 dígitos, primero multiplíquelo por 1000, redondéelo y divida el resultado redondeado por 1000:

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

Aparte de cualquier tipo de soluciones printf(...) o String(format: ...), el resultado de esta operación sigue siendo de tipo Double.

EDITAR:
En cuanto a los comentarios que a veces no funciona, por favor lea esto:

Lo Que Todo Científico De La Computación Debe Saber Aritmética de coma flotante

 269
Author: zisoft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-28 18:34:26

Extensión para Swift 2

Una solución más general es la siguiente extensión, que funciona con Swift 2 e 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 round se sustituye 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
 358
Author: Sebastian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-16 05:18:43

Usa el constructor String que toma una cadena format:

print(String(format: "%.3f", totalWorkTimeInHours))
 213
Author: vacawama,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-01 16:43:30

Con Swift 4, según sus necesidades, puede elegir uno de los 9 siguientes estilos para obtener un resultado redondeado de un Double.


#1. Usando FloatingPoint rounded() método

En el caso más simple, puede utilizar el Double round() método.

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. Usando FloatingPoint rounded(_:) método

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. Usando la función Darwin round

Foundation ofrece una función round a 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 extensión Double construido con Darwin round y pow funciones

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. Usando NSDecimalNumber rounding(accordingToBehavior:) método

Si es necesario, NSDecimalNumber ofrece una solución detallada pero potente 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. Usando 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. Usando NSString init(format:arguments:) inicializador

Si desea devolver un NSString de su operación de redondeo, usar NSString initializer 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 String de Swift se puentea con la clase NSString de Foundation (puede obtener más información al respecto leyendo El Lenguaje de programación Swift). Por lo tanto, puede utilizar el siguiente código en para devolver un 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 un String? de 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")
 130
Author: Imanou Petit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-16 01:07:08

En Swift 2.0 y Xcode 7.2:

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

Ejemplo:

introduzca la descripción de la imagen aquí

 79
Author: Claudio Guirunas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-20 10:32:40

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
}
 24
Author: Ash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-04 11:22:19

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

 16
Author: Krunal Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-27 10:45:20

En Swift 3.0 y Xcode 8.0:

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

Usa esta extensión así,

let doubleValue = 3.567
let roundedValue = doubleValue.roundTo(places: 2)
print(roundedValue) // prints 3.56
 13
Author: jaiswal Rajan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-19 05:00:06

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 al swift que redondee este número a 3 decimales.y si quieres número doble, puedes usar este código:

/ / String to Double

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

 13
Author: Ramazan Karami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-04 06:30:24

Un modo práctico puede ser el uso de 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
 8
Author: Marco Leong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-11 12:56:43

Utilice la biblioteca incorporada 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

 7
Author: George Filippakos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-30 23:41:21

Esta es una especie de solución larga, que puede ser útil si sus necesidades son un poco más complejas. Puede utilizar un formateador de números en Swift.

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

Supongamos que la 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 la OP mencionó la impresión (en cuyo caso una cadena no es indeseable), y porque esta clase permite establecer múltiples parámetros.

 6
Author: Inkidu616,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-14 22:08:59

Usaría

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

Y cambiar .3f a cualquier número de números decimales que necesita

 6
Author: Mohsen Hossein pour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-27 12:24:59

No es rápido, pero estoy seguro de que entiendes la idea.

pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
 4
Author: yogi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-08 00:12:22

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
 4
Author: Nikita Ivaniushchenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-07 19:44:13

Redondee un valor doble a x número de decimal
NO. de dígitos después del 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
 4
Author: Ayman Badr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-21 11:53:24

La mejor manera de formatear una propiedad double es usar 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:

Caso AwayFromZero Redondee al valor permitido más cercano cuya magnitud sea mayor o igual a la de la fuente.

Case down Redondee al valor permitido más cercano que sea menor o igual a la fuente.

Caso Una o dos veces desde Cero Redondea al valor permitido más cercano; si dos valores están igualmente cerca, se elige el de mayor magnitud.

Caso ton Reestoreven Redondee al valor permitido más cercano;si dos valores están igualmente cerca, se elige el par.

Case towardZero Redondee al valor permitido más cercano cuya magnitud sea menor o igual a la de la fuente.

Case up Redondear al valor permitido más cercano que sea mayor que o igual a la fuente.

var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0
 3
Author: Abuzar Manzoor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-05 14:22:55

O bien:

  1. Usando String(format:):

    • Encasillado Double a String con %.3f especificador de formato y, a continuación, volver a Double

      Double(String(format: "%.3f", 10.123546789))!
      
    • O extender Double para manejar N-Decimales:

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

    • Multiplicar por 10^3, redondearlo y luego dividir por 10^3...

      (1000 * 10.123546789).rounded()/1000
      
    • O extender Double para manejar N-Decimal lugares:

      extension Double {    
          func rounded(toDecimalPlaces n: Int) -> Double {
              let multiplier = pow(10, Double(n))
              return (multiplier * self).rounded()/multiplier
          }
      }
      
 3
Author: staticVoidMan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-20 09:39:01

Si desea redondear los valores Double, es posible que desee usar Swift Decimal para no introducir ningún error que pueda surgir al intentar matemáticas con estos valores redondeados. Si utiliza Decimal, puede representar con precisión los valores decimales de ese valor de coma flotante redondeado.

Así que puedes hacer:

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

Entonces, puedes obtener el valor redondeado Decimal así:

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

Y si desea mostrarlo con un número especificado de lugares decimales (así como localizar la cadena para el local actual del usuario), puede utilizar un NumberFormatter:

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

if let string = formatter.string(for: value) {
    print(string)
}
 1
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-05 07:36:38

Encontré esto preguntándome si es posible corregir la entrada de un usuario. Eso es si ingresan tres decimales en lugar de dos por una cantidad en dólares. Digamos 1.111 en lugar de 1.11 ¿puedes arreglarlo redondeando? La respuesta por muchas razones es no! Con el dinero cualquier cosa sobre es decir 0.001 causaría eventual problemas en una chequera verdadera.

Aquí hay una función para verificar que los usuarios ingresen demasiados valores después del período. Pero que permitirá 1., 1.1 y 1.11.

Se supone que el el valor ya se ha comprobado para la conversión exitosa de una cadena a un Doble.

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


}
 0
Author: Mountain Man,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-06 01:03:59
//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"
 0
Author: Davender Verma Soni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-28 09:45:52