¿Cómo redondear un doble al int más cercano en swift?

170

Estoy tratando de hacer una calculadora de la tasa de crecimiento ( Double) que redondeará el resultado al número entero más cercano y volverá a calcular desde allí, como tal:

let firstUsers = 10.0
let growth = 0.1
var users = firstUsers
var week = 0


while users < 14 {
    println("week \(week) has \(users) users")
    users += users * growth
    week += 1
}

pero hasta ahora no he podido.

EDITAR Lo hice así:

var firstUsers = 10.0
let growth = 0.1
var users:Int = Int(firstUsers)
var week = 0


while users <= 14 {
    println("week \(week) has \(users) users")
    firstUsers += firstUsers * growth
    users = Int(firstUsers)
    week += 1
}

Aunque no me importa que siempre se esté redondeando, no me gusta porque firstUserstuvo que convertirse en una variable y cambiar a lo largo del programa (para hacer el siguiente cálculo), lo que no quiero que suceda.

duarte harris
fuente

Respuestas:

253

Hay una rounddisponible en la Foundationbiblioteca (en realidad está dentro Darwin, pero Foundationimporta Darwiny la mayoría de las veces querrás usar en Foundationlugar de usar Darwindirectamente) .

import Foundation

users = round(users)

Ejecuta tu código en un patio de recreo y luego llama:

print(round(users))

Salidas:

15,0

round()siempre se redondea hacia arriba cuando el lugar decimal es >= .5y hacia abajo cuando es < .5(redondeo estándar). Puede usar floor()para forzar el redondeo hacia abajo, yceil() para forzar el redondeo hacia arriba.

Si necesita redonda a un lugar específico, entonces se multiplica por pow(10.0, number of places), roundy, a continuación, dividir porpow(10, number of places) :

Redondear a 2 decimales:

let numberOfPlaces = 2.0
let multiplier = pow(10.0, numberOfPlaces)
let num = 10.12345
let rounded = round(num * multiplier) / multiplier
print(rounded)

Salidas:

10.12

Nota: Debido a la forma en que funcionan las matemáticas de coma flotante, es roundedposible que no siempre sean perfectamente precisas. Es mejor pensarlo más como una aproximación de redondeo. Si está haciendo esto para fines de visualización, es mejor usar el formato de cadena para formatear el número en lugar de usar las matemáticas para redondearlo.

Mike S
fuente
Hmm pow()desafortunadamente no está disponible en un patio de juegos
MrBr
1
@MrBr, pow()se define en la biblioteca de Darwin, lo que es necesario import Darwinen primer lugar (o import Foundation, o import Cocoa, o import UIKit, todo lo cual termina la importación de Darwin internamente).
Mike S
54
También hay lround()que devuelve un Int.
Martin R
1
" round()siempre se redondea hacia arriba cuando el decimal es> = .5 y hacia abajo cuando es <.5 (redondeo estándar)". Excepto cuando no lo hace. round(-16.5)devuelve -17, no -16. ¿Es esto un error?
Daniel T.
1
@DanielT. No es un error. Se está redondeando al número negativo más grande más cercano. Piénselo de esta manera, +16.5 a +17 se está moviendo 0.5 más lejos de cero. Eso significa que -16.5 a -17 también está 0.5 más lejos de cero. Techo sería lo contrario, +16.5 a +16 es 0.5 más cerca de cero y -16.5 a -16 también es 0.5 más cerca de cero
adougies
139

Para redondear un doble al entero más cercano, solo use round().

var x = 3.7
x.round() // x = 4.0

Si no desea modificar el valor original, use rounded():

let x = 3.7
let y = x.rounded() // y = 4.0. x = 3.7

Como cabría esperar ( o no ), un número como 3.5se redondea hacia arriba y un número como -3.5se redondea hacia abajo. Si necesita un comportamiento de redondeo diferente, puede usar una de las reglas de redondeo . Por ejemplo:

var x = 3.7
x.round(.towardZero) // 3.0

Si necesita un real Int, simplemente se lo emite a uno (pero solo si está seguro de que el Doble no será mayor que Int.max):

let myInt = Int(myDouble.rounded())

Notas

  • Esta respuesta está completamente reescrita. Mi vieja respuesta se ocupó de la C funciones matemáticas como round, lround, floor, y ceil. Sin embargo, ahora que Swift tiene esta funcionalidad incorporada, ya no puedo recomendar el uso de esas funciones. Gracias a @dfri por señalarme esto. Mira la excelente respuesta de @ dfri aquí . También hice algo similar para redondear aCGFloat .
Suragch
fuente
Int (myDouble. round ()) <--- esto podría arrojar una excepción si el doble no se ajusta al Int
Toad
@Toad, ¿estás seguro? No veo eso en la documentación .
Suragch
Acabo de resolver un bloqueo en la producción con este problema exacto. Pero incluso si estaba equivocado y no se estrellaba, aún así daría resultados inesperados para dobles> maxint
Toad
1
@ Sapo, cierto, buen punto, gracias. Agregué una nota a la respuesta.
Suragch
85

Swift 3 y 4: haciendo uso del rounded(_:)método como se muestra en el FloatingPointprotocolo

El FloatingPointprotocolo (al cual, por ejemplo, Doubley se Floatajusta) esboza el rounded(_:)método

func rounded(_ rule: FloatingPointRoundingRule) -> Self

¿Dónde FloatingPointRoundingRulehay una enumeración que enumera una serie de reglas de redondeo diferentes:

case awayFromZero

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

case down

Redondea al valor permitido más cercano que sea menor o igual que la fuente.

case toNearestOrAwayFromZero

Redondear al valor permitido más cercano; Si dos valores son igualmente cercanos, se elige el de mayor magnitud.

case toNearestOrEven

Redondear al valor permitido más cercano; Si dos valores son igualmente cercanos, se elige el par.

case towardZero

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

case up

Redondea al valor permitido más cercano que sea mayor o igual que la fuente.

Utilizamos ejemplos similares a los de la excelente respuesta de @ Suragch para mostrar estas diferentes opciones de redondeo en la práctica.

.awayFromZero

Redondee al valor permitido más cercano cuya magnitud sea mayor o igual que la de la fuente; no hay equivalente directo entre las funciones de C, ya que esto utiliza, condicionalmente en el signo de self, ceilo floor, para valores positivos y negativos de self, respectivamente.

3.000.rounded(.awayFromZero) // 3.0
3.001.rounded(.awayFromZero) // 4.0
3.999.rounded(.awayFromZero) // 4.0

(-3.000).rounded(.awayFromZero) // -3.0
(-3.001).rounded(.awayFromZero) // -4.0
(-3.999).rounded(.awayFromZero) // -4.0

.down

Equivalente a la floorfunción C.

3.000.rounded(.down) // 3.0
3.001.rounded(.down) // 3.0
3.999.rounded(.down) // 3.0

(-3.000).rounded(.down) // -3.0
(-3.001).rounded(.down) // -4.0
(-3.999).rounded(.down) // -4.0

.toNearestOrAwayFromZero

Equivalente a la roundfunción C.

3.000.rounded(.toNearestOrAwayFromZero) // 3.0
3.001.rounded(.toNearestOrAwayFromZero) // 3.0
3.499.rounded(.toNearestOrAwayFromZero) // 3.0
3.500.rounded(.toNearestOrAwayFromZero) // 4.0
3.999.rounded(.toNearestOrAwayFromZero) // 4.0

(-3.000).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.001).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.499).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.500).rounded(.toNearestOrAwayFromZero) // -4.0
(-3.999).rounded(.toNearestOrAwayFromZero) // -4.0

También se puede acceder a esta regla de redondeo utilizando el rounded()método de argumento cero .

3.000.rounded() // 3.0
// ...

(-3.000).rounded() // -3.0
// ...

.toNearestOrEven

Redondear al valor permitido más cercano; si dos valores son igualmente cercanos, se elige el par; equivalente a la función C rint(/ muy similar a nearbyint).

3.499.rounded(.toNearestOrEven) // 3.0
3.500.rounded(.toNearestOrEven) // 4.0 (up to even)
3.501.rounded(.toNearestOrEven) // 4.0

4.499.rounded(.toNearestOrEven) // 4.0
4.500.rounded(.toNearestOrEven) // 4.0 (down to even)
4.501.rounded(.toNearestOrEven) // 5.0 (up to nearest)

.towardZero

Equivalente a la truncfunción C.

3.000.rounded(.towardZero) // 3.0
3.001.rounded(.towardZero) // 3.0
3.999.rounded(.towardZero) // 3.0

(-3.000).rounded(.towardZero) // 3.0
(-3.001).rounded(.towardZero) // 3.0
(-3.999).rounded(.towardZero) // 3.0

Si el propósito del redondeo es prepararse para trabajar con un número entero (por ejemplo, usando Intpor FloatPointinicialización después del redondeo), podríamos simplemente hacer uso del hecho de que al inicializar un Intuso de a Double(o Floatetc.), la parte decimal se truncará.

Int(3.000) // 3
Int(3.001) // 3
Int(3.999) // 3

Int(-3.000) // -3
Int(-3.001) // -3
Int(-3.999) // -3

.up

Equivalente a la ceilfunción C.

3.000.rounded(.up) // 3.0
3.001.rounded(.up) // 4.0
3.999.rounded(.up) // 4.0

(-3.000).rounded(.up) // 3.0
(-3.001).rounded(.up) // 3.0
(-3.999).rounded(.up) // 3.0

Anexo: visitando el código fuente para FloatingPointverificar la equivalencia de las funciones C con los diferentesFloatingPointRoundingRule reglas

Si quisiéramos, podemos echar un vistazo al código fuente del FloatingPointprotocolo para ver directamente los equivalentes de la función C al públicoFloatingPointRoundingRule reglas .

Desde swift / stdlib / public / core / FloatingPoint.swift.gyb , vemos que la implementación predeterminada del rounded(_:)método nos convierte en el round(_:)método de mutación :

public func rounded(_ rule: FloatingPointRoundingRule) -> Self {
    var lhs = self
    lhs.round(rule)
    return lhs
}

En swift / stdlib / public / core / FloatingPointTypes.swift.gyb encontramos la implementación predeterminada de round(_:), en la que la equivalencia entre las FloatingPointRoundingRulereglas y las funciones de redondeo en C es evidente:

public mutating func round(_ rule: FloatingPointRoundingRule) {
    switch rule {
    case .toNearestOrAwayFromZero:
        _value = Builtin.int_round_FPIEEE${bits}(_value)
    case .toNearestOrEven:
        _value = Builtin.int_rint_FPIEEE${bits}(_value)
    case .towardZero:
        _value = Builtin.int_trunc_FPIEEE${bits}(_value)
    case .awayFromZero:
        if sign == .minus {
            _value = Builtin.int_floor_FPIEEE${bits}(_value)
        }
        else {
            _value = Builtin.int_ceil_FPIEEE${bits}(_value)
        }
    case .up:
        _value = Builtin.int_ceil_FPIEEE${bits}(_value)
    case .down:
        _value = Builtin.int_floor_FPIEEE${bits}(_value)
    }
}
dfri
fuente
@iosMentalist gracias por el aviso, he actualizado el título de la respuesta.
dfri
Si quiero alguna ecuación como, 3.0 = 3, 3.1 = 3.5, 3.4 = 3.5, 3.6 = 4, 3.9 - 4
PJR
6
**In Swift**

var a = 14.123456789
var b = 14.123456789
var c = 14.123456789
var d = 14.123456789
var e = 14.123456789
var f = 14.123456789

a.rounded(.up)                      //15
b.rounded(.down)                    //14
c.rounded(.awayFromZero)            //15
d.rounded(.towardZero)              //14
e.rounded(.toNearestOrAwayFromZero) //14
f.rounded(.toNearestOrEven)         //14
Sai kumar Reddy
fuente
6

Swift 3: si desea redondear a un cierto número de dígitos, por ejemplo 5.678434 -> 5.68, puede combinar la función round () o roundf () con una multiplicación:

let value:Float = 5.678434
let roundedValue = roundf(value * 100) / 100
print(roundedValue) //5.68
Thoms
fuente
4

También puede extender FloatingPoint en Swift 3 de la siguiente manera:

extension FloatingPoint {
    func rounded(to n: Int) -> Self {
        let n = Self(n)
        return (self / n).rounded() * n

    }
}

324.0.rounded(to: 5)   // 325
Leo Dabus
fuente
Puede usted explicar esto? Que Selfsignifica
JZAU
@Jacky Self se refiere a la clase FloatingPoint, mientras que self se refiere a la instancia de esa clase.
George Yacoub
@GeorgeYacoub Self se refiere al tipo que se ajusta a FloatingPoint que se está extendiendo (en ese uso de muestra es un Doble) pero son estructuras, no clases
Leo Dabus
2

Swift 3

var myNum = 8.09
myNum.rounded() // result = 8 and leaves myNum unmodified
Dattatray Deokar
fuente
Agradable. No sabía sobre esto antes. Una nota: myNum.rounded()no cambia myNum, pero lo myNum.round()hace.
Suragch
@Suragch, he editado la respuesta para reflejar tu comentario.
Adil Hussain
0

También es posible que desee verificar si el doble es más alto que el valor máximo de Int antes de intentar convertir el valor en Int.

let number = Double.infinity
if number >= Double(integerLiteral: Int64.max) {
  let rounded = Int.max
} else {
  let rounded = Int(number.rounded())
}
rockdaswift
fuente
-1

Una solución muy fácil funcionó para mí:

  if (62 % 50 != 0) {
      var number = 62 / 50 + 1 // adding 1 is doing the actual "round up"
  }

el número contiene el valor 2

Nazar Medeiros
fuente