Come arrotondare rapidamente un doppio all'int più vicino?


170

Sto cercando di creare un calcolatore del tasso di crescita ( Double) che arrotonderà il risultato al numero intero più vicino e ricalcolerà da lì, come tale:

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
}

ma finora non sono stato in grado.

EDIT Ho fatto un po 'così:

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
}

Anche se non mi dispiace che sia sempre arrotondato per difetto, non mi piace perché firstUsersdoveva diventare una variabile e cambiare in tutto il programma (al fine di fare il prossimo calcolo), che non voglio che accada.

Risposte:


253

C'è un rounddisponibile nella Foundationlibreria (in realtà è Darwin, ma Foundationimporta Darwine il più delle volte ti consigliamo di utilizzare Foundationinvece di utilizzare Darwindirettamente) .

import Foundation

users = round(users)

Eseguendo il codice in un parco giochi e quindi chiamando:

print(round(users))

Uscite:

15.0

round()arrotonda sempre quando il decimale è >= .5e diminuisce quando è < .5(arrotondamento standard). È possibile utilizzare floor()per forzare l'arrotondamento per difetto e ceil()per forzare l'arrotondamento.

Se avete bisogno di turno ad un luogo specifico, allora si moltiplicare per pow(10.0, number of places), rounde poi dividere per pow(10, number of places):

Arrotondare al secondo decimale:

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

Uscite:

10.12

Nota: a causa del modo in cui funziona la matematica in virgola mobile, roundedpotrebbe non essere sempre perfettamente preciso. È meglio pensarci più come un'approssimazione dell'arrotondamento. Se lo stai facendo a scopo di visualizzazione, è meglio usare la formattazione delle stringhe per formattare il numero piuttosto che usare la matematica per arrotondarlo.


Hmm pow()purtroppo non disponibile in un parco giochi
MrBr

1
@MrBr, pow()è definito nella libreria Darwin, quindi devi import Darwinprima (o import Foundationo import Cocoao import UIKit, tutto ciò che finisce per importare Darwin internamente).
Mike S,

54
C'è anche lround()che restituisce un Int.
Martin R

1
" round()arrotonda sempre quando il decimale è> = .5 e verso il basso quando è <.5 (arrotondamento standard)." Tranne quando non lo fa. round(-16.5)restituisce -17, non -16. è un insetto?
Daniel T.

1
@DanielT. - non un bug. Arrotonda per eccesso al numero negativo più grande più vicino. Pensaci in questo modo, da +16,5 a +17 si sta allontanando di 0,5 da zero. Ciò significa che da -16,5 a -17 è anche 0,5 più lontano da zero. Il cemento sarebbe l'opposto, da +16,5 a +16 è 0,5 più vicino a zero e da -16,5 a -16 è anche 0,5 più vicino a zero
adougies

139

Per arrotondare un doppio all'intero più vicino, basta usare round().

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

Se non si desidera modificare il valore originale, utilizzare rounded():

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

Come ci si potrebbe aspettare ( o no ), un numero come 3.5è arrotondato per eccesso e un numero come -3.5è arrotondato per difetto. Se è necessario un comportamento di arrotondamento diverso da quello, è possibile utilizzare una delle regole di arrotondamento . Per esempio:

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

Se hai bisogno di un vero Inte proprio cast, basta lanciarlo su uno (ma solo se sei sicuro che il Double non sarà maggiore di Int.max):

let myInt = Int(myDouble.rounded())

Appunti

  • Questa risposta è stata completamente riscritta. La mia risposta vecchia affrontato il C funzioni matematiche piace round, lround, floor, e ceil. Tuttavia, ora che Swift ha questa funzionalità integrata, non posso più raccomandare di utilizzare tali funzioni. Grazie a @dfri per avermelo segnalato. Scopri @ eccellente risposta di dfri qui . Ho anche fatto qualcosa di simile per arrotondare aCGFloat .

Int (myDouble.rounded ()) <--- questo potrebbe effettivamente generare un'eccezione se il doppio non si adatta a Int
Rospo

@Toad, sei sicuro? Non lo vedo nella documentazione .
Suragch,

Ho appena risolto un arresto anomalo della produzione con questo problema esatto. Ma anche se avessi torto e non si arrestasse in modo anomalo, continuerebbe comunque a dare risultati inaspettati per i doppi> maxint
Rospo

1
@Toad, giusto, buon punto, grazie. Ho aggiunto una nota alla risposta.
Suragch,

85

Swift 3 & 4 - facendo uso del rounded(_:)metodo come indicato nel FloatingPointprotocollo

Il FloatingPointprotocollo (al quale ad esempio Doublee Floatconforme) progetta il rounded(_:)metodo

func rounded(_ rule: FloatingPointRoundingRule) -> Self

Dov'è FloatingPointRoundingRuleun'enum che elenca un numero di diverse regole di arrotondamento:

case awayFromZero

Arrotonda al valore consentito più vicino la cui grandezza è maggiore o uguale a quella della sorgente.

case down

Arrotondare al valore consentito più vicino che è minore o uguale alla fonte.

case toNearestOrAwayFromZero

Arrotondare al valore consentito più vicino; se due valori sono ugualmente vicini, viene scelto quello con maggiore magnitudine.

case toNearestOrEven

Arrotondare al valore consentito più vicino; se due valori sono ugualmente vicini, viene scelto quello pari.

case towardZero

Arrotonda al valore consentito più vicino la cui grandezza è inferiore o uguale a quella della sorgente.

case up

Arrotondare al valore consentito più vicino maggiore o uguale alla fonte.

Facciamo uso di esempi simili a quelli dell'eccellente risposta di @ Suragch per mostrare in pratica queste diverse opzioni di arrotondamento.

.awayFromZero

Arrotonda al valore consentito più vicino la cui grandezza è maggiore o uguale a quella della sorgente; non diretta equivalente tra le funzioni C, in quanto questo tipo di uso, condizionatamente segno self, ceilo floor, per valori positivi e negativi di self, rispettivamente.

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 alla floorfunzione 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 alla roundfunzione 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

È possibile accedere a questa regola di arrotondamento anche utilizzando il rounded()metodo argomento zero .

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

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

.toNearestOrEven

Arrotondare al valore consentito più vicino; se due valori sono ugualmente vicini, viene scelto anche quello; equivalente alla funzione C rint(/ molto simile 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 alla truncfunzione 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

Se lo scopo dell'arrotondamento è quello di preparare a lavorare con un intero (ad esempio utilizzando Intda FloatPointinizializzazione dopo l'arrotondamento), potremmo semplicemente fare uso del fatto che quando si inizializza un Intutilizza una Double(o Float, ecc), la parte decimale verrà troncata via.

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 alla ceilfunzione 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

Addendum: visita del codice sorgente per FloatingPointverificare l'equivalenza delle funzioni C alle diverse FloatingPointRoundingRuleregole

Se vorremmo, possiamo dare un'occhiata al codice sorgente del FloatingPointprotocollo per vedere direttamente la funzione C equivalente alle FloatingPointRoundingRuleregole pubbliche .

Da swift / stdlib / public / core / FloatingPoint.swift.gyb vediamo che l'implementazione predefinita del rounded(_:)metodo ci rende il round(_:)metodo mutante :

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

Da swift / stdlib / public / core / FloatingPointTypes.swift.gyb troviamo l'implementazione predefinita di round(_:), in cui FloatingPointRoundingRuleè evidente l'equivalenza tra le regole e le funzioni di arrotondamento C:

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

@iosMentalist grazie per la richiesta, ho aggiornato il titolo della risposta.
venerdì

Se voglio un'equazione simile, 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

6

Swift 3: se vuoi arrotondare ad un certo numero di cifre, ad es. 5.678434 -> 5.68 puoi semplicemente combinare la funzione round () o roundf () con una moltiplicazione:

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

4

Puoi anche estendere FloatingPoint in Swift 3 come segue:

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

    }
}

324.0.rounded(to: 5)   // 325

Puoi per favore spiegare questo? Che cosa Selfsignifica?
JZAU

@Jacky Self si riferisce alla classe FloatingPoint mentre self si riferisce all'istanza di quella classe.
George Yacoub,

@GeorgeYacoub Self si riferisce al tipo conforme a FloatingPoint che viene esteso (in quel campione l'utilizzo è un doppio) ma sono strutture, non classi
Leo Dabus

2

Swift 3

var myNum = 8.09
myNum.rounded() // result = 8 and leaves myNum unmodified

Bello. Non lo sapevo prima. Una nota: myNum.rounded()non cambia myNum, ma cambia myNum.round().
Suragch,

@Suragch, ho modificato la risposta per riflettere il tuo commento.
Adil Hussain,

0

Puoi anche verificare se il doppio è superiore al valore Int massimo prima di provare a convertire il valore in Int.

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

-1

Una soluzione molto semplice ha funzionato per me:

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

il numero contiene il valore 2

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.