swift - libro - ¿Cómo redondear un doble al int más cercano a la vez?
fahrenheit 451 ray bradbury (6)
Estoy tratando de hacer una calculadora de la tasa de crecimiento ( Double
) que redondeará el resultado al entero más cercano y volverá a calcular a partir de 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 no he podido hasta ahora.
EDITAR Yo 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 esté redondeando, no me gusta porque los firstUsers
tenían que convertirse en una variable y cambiar a lo largo del programa (para hacer el siguiente cálculo), lo que no quiero que suceda. .
Swift 3: haciendo uso del método rounded(_:)
tal como se imprimió en el protocolo FloatingPoint
El protocolo FloatingPoint
(al cual, por ejemplo, Double
y Float
ajusta) dibuja el rounded()
func rounded(_ rule: FloatingPointRoundingRule) -> Self
Donde FloatingPointRoundingRule
es una enumeración que enumera una serie de reglas de redondeo diferentes:
case awayFromZero
Redondea al valor permitido más cercano cuya magnitud sea mayor o igual a la de la fuente.
case down
Redondea al valor permitido más cercano que sea menor o igual que la fuente.
case toNearestOrAwayFromZero
Redondea al valor permitido más cercano; si dos valores son igualmente cercanos, se elige el de mayor magnitud.
case toNearestOrEven
Redondea al valor permitido más cercano; si dos valores son igualmente cercanos, se elige el par.
case towardZero
Redondea al valor permitido más cercano cuya magnitud sea menor o igual a la de la fuente.
case up
Redondea al valor permitido más cercano que sea mayor o igual que la fuente.
Hacemos uso de 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 a la de la fuente; no existe un equivalente directo entre las funciones C, ya que esto utiliza, condicionalmente, el signo de self
, ceil
o 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 función de floor
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 función C round
.
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 método zero argument rounded()
.
3.000.rounded() // 3.0
// ...
(-3.000).rounded() // -3.0
// ...
.toNearestOrEven
Redondea 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) // 4.0
.towardZero
Equivalente a la función C trunc
.
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 Int
por inicialización de FloatPoint
después del redondeo), podríamos simplemente utilizar el hecho de que al inicializar un Int
usando un Double
(o Float
etc.), la parte decimal será truncado.
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 función C ceil
.
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
Adición: visitar el código fuente de FloatingPoint
para verificar la equivalencia de las funciones C a las diferentes reglas de FloatingPointRoundingRule
Si queremos, podemos echar un vistazo al código fuente del protocolo FloatingPoint
para ver directamente las funciones C equivalentes a las reglas públicas de FloatingPointRoundingRule
.
Desde swift/stdlib/public/core/FloatingPoint.swift.gyb vemos que la implementación predeterminada del método rounded(_:)
nos hace del método de la round(_:)
mutación round(_:)
:
public func rounded(_ rule: FloatingPointRoundingRule) -> Self { var lhs = self lhs.round(rule) return lhs }
Desde swift/stdlib/public/core/FloatingPointTypes.swift.gyb encontramos la implementación predeterminada de round(_:)
, en la cual la equivalencia entre las reglas de FloatingPointRoundingRule
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) } }
Hay una round
disponible en la biblioteca de la Foundation
(en realidad está en Darwin
, pero la Foundation
importa Darwin
y la mayoría de las veces querrás usar Foundation
lugar de usar Darwin
directamente) .
import Foundation
users = round(users)
Ejecutando su código en un patio de recreo y luego llamando:
print(round(users))
Productos:
15.0
round()
siempre redondea cuando el lugar decimal es >= .5
y hacia abajo cuando es < .5
(redondeo estándar). Puede usar floor()
para forzar el redondeo hacia abajo y ceil()
para forzar el redondeo hacia arriba.
Si necesita redondear a un lugar específico, entonces multiplica por pow(10.0, number of places)
, round
, y luego divide por pow(10, number of places)
:
Ronda a 2 decimales:
let numberOfPlaces = 2.0
let multiplier = pow(10.0, numberOfPlaces)
let num = 10.12345
let rounded = round(10.12345 * multiplier) / multiplier
print(rounded)
Productos:
10.12
Nota: Debido a la forma en que funciona la matemática de coma flotante, rounded
puede no ser siempre perfecta. Lo mejor es pensar más en una aproximación de redondeo. Si está haciendo esto para fines de visualización, es mejor usar el formato de cadenas para formatear el número en lugar de usar las matemáticas para redondearlo.
Para redondear un doble al entero más cercano, solo usa round()
.
var x = 3.7
x.round() // x = 4.0
Si no desea modificar el valor original, utilice rounded()
:
let x = 3.7
let y = x.rounded() // y = 4.0. x = 3.7
Como uno podría esperar ( o no ), un número como 3.5
se redondea hacia arriba y un número como -3.5
se 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 una Int
real, simplemente conviértala en una:
let myInt = Int(myDouble.rounded())
Notas
- Esta respuesta está completamente reescrita. Mi respuesta anterior se refería a las funciones matemáticas C, como
round
,lround
,floor
yceil
. 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. Vea la excelente respuesta de @dfri aquí . También hice algo similar para redondear unCGFloat
.
Swift 3
var myNum = 8.09
myNum.rounded () // result = 8 que se almacena en myNum
Swift 3: si desea redondear a un cierto número de dígitos, por ejemplo, 5.678434 -> 5.68, puede simplemente 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
También puede extender FloatingPoint en Swift 3 de la siguiente manera:
extension FloatingPoint {
func rounded(to n: Int) -> Self {
return (self / Self(n)).rounded() * Self(n)
}
}
324.0.rounded(to: 5) // 325