Wie kann man ein Double schnell auf das nächste Int runden?

170

Ich versuche, einen Rechner für die Wachstumsrate ( Double) zu erstellen, der das Ergebnis auf die nächste Ganzzahl rundet und von dort aus neu berechnet:

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
}

aber ich war bisher nicht in der Lage.

BEARBEITEN Ich habe es irgendwie so gemacht:

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
}

Obwohl es mir nichts ausmacht, dass es immer abgerundet wird, mag ich es nicht, weil firstUserses eine Variable werden und sich im Laufe des Programms ändern musste (um die nächste Berechnung durchzuführen), was ich nicht möchte, dass es passiert.

duarte harris
quelle

Antworten:

253

roundIn der FoundationBibliothek ist eine verfügbar (tatsächlich in Darwin, aber FoundationImporte Darwinund die meiste Zeit möchten Sie verwenden, Foundationanstatt Darwindirekt zu verwenden) .

import Foundation

users = round(users)

Führen Sie Ihren Code auf einem Spielplatz aus und rufen Sie dann an:

print(round(users))

Ausgänge:

15.0

round()rundet immer auf, wenn die Dezimalstelle ist, >= .5und ab, wenn es ist < .5(Standardrundung). Sie können verwenden floor(), um das Abrunden und ceil()das Aufrunden zu erzwingen.

Wenn Sie rund um einen bestimmten Ort benötigen, dann multiplizieren Sie durch pow(10.0, number of places), roundund dann teilen , indem er pow(10, number of places):

Auf 2 Dezimalstellen runden:

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

Ausgänge:

10.12

Hinweis: Aufgrund der Funktionsweise der Gleitkomma-Mathematik ist diese roundedmöglicherweise nicht immer genau. Es ist am besten, sich das eher als Annäherung an die Rundung vorzustellen. Wenn Sie dies zu Anzeigezwecken tun, ist es besser, die Zahl mithilfe der Zeichenfolgenformatierung zu formatieren, als sie mit Mathematik zu runden.

Mike S.
quelle
Hmm pow()leider nicht auf einem Spielplatz verfügbar
MrBr
1
@MrBr pow()ist in der Darwin-Bibliothek definiert, daher müssen Sie import Darwinzuerst (oder import Foundationoder import Cocoaoder import UIKit, die alle Darwin intern importieren).
Mike S
54
Es gibt auch lround()welche eine zurückgibt Int.
Martin R
1
" round()Rundet immer auf, wenn die Dezimalstelle> = .5 ist, und ab, wenn es <.5 ist (Standardrundung)." Außer wenn es nicht so ist. round(-16.5)gibt -17 zurück, nicht -16. Ist das ein Fehler?
Daniel T.
1
@ DanielT. - Kein Fehler. Es wird auf die nächstgrößere negative Zahl aufgerundet. Stellen Sie sich das so vor: +16,5 bis +17 bewegen sich 0,5 weiter von Null weg. Das heißt, -16,5 bis -17 sind auch 0,5 weiter von Null entfernt. Decke wäre das Gegenteil, +16,5 bis +16 ist 0,5 näher an Null und -16,5 bis -16 ist auch 0,5 näher an Null
adougies
139

Verwenden Sie einfach, um ein Double auf die nächste Ganzzahl zu runden round().

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

Wenn Sie den ursprünglichen Wert nicht ändern möchten, verwenden Sie rounded():

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

Wie zu erwarten ( oder auch nicht ) wird eine Zahl wie 3.5aufgerundet und eine Zahl wie -3.5abgerundet. Wenn Sie ein anderes Rundungsverhalten benötigen, können Sie eine der Rundungsregeln verwenden . Beispielsweise:

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

Wenn Sie eine tatsächliche benötigen, wandeln Sie sie Inteinfach in eine um (aber nur, wenn Sie sicher sind, dass das Double nicht größer ist als Int.max):

let myInt = Int(myDouble.rounded())

Anmerkungen

  • Diese Antwort wurde komplett neu geschrieben. Meine alte Antwort befasste sich mit dem C mathematischen Funktionen wie round, lround, floor, und ceil. Nachdem Swift diese Funktionalität integriert hat, kann ich die Verwendung dieser Funktionen nicht mehr empfehlen. Vielen Dank an @dfri für den Hinweis. Schauen Sie sich hier die ausgezeichnete Antwort von @ dfri an . Ich habe auch etwas Ähnliches gemacht, um a zu rundenCGFloat .
Suragch
quelle
Int (myDouble.rounded ()) <--- Dies könnte tatsächlich eine Ausnahme auslösen, wenn das Double nicht zur Int
Toad
@Toad, bist du sicher? Ich sehe das nicht in der Dokumentation .
Suragch
Ich habe gerade einen Absturz in der Produktion mit genau diesem Problem gelöst. Aber selbst wenn ich mich geirrt hätte und es nicht abstürzen würde, würde es dennoch unerwartete Ergebnisse für Doppel> maxint
Toad
1
@Toad, richtig, guter Punkt, danke. Ich habe der Antwort eine Notiz hinzugefügt.
Suragch
83

Swift 3 & 4 - Verwendung der rounded(_:)im FloatingPointProtokoll festgelegten Methode

Das FloatingPointProtokoll (zB , zu der Doubleund FloatKonform) Items herzustellen das rounded(_:)Verfahren

func rounded(_ rule: FloatingPointRoundingRule) -> Self

Wo FloatingPointRoundingRuleist eine Aufzählung, die eine Reihe verschiedener Rundungsregeln auflistet:

case awayFromZero

Runden Sie auf den nächsten zulässigen Wert, dessen Größe größer oder gleich der der Quelle ist.

case down

Runden Sie auf den nächsten zulässigen Wert, der kleiner oder gleich der Quelle ist.

case toNearestOrAwayFromZero

Auf den nächsten zulässigen Wert runden; Wenn zwei Werte gleich nahe beieinander liegen, wird der mit der größeren Größe ausgewählt.

case toNearestOrEven

Auf den nächsten zulässigen Wert runden; Wenn zwei Werte gleich nahe beieinander liegen, wird der gerade gewählt.

case towardZero

Runden Sie auf den nächsten zulässigen Wert, dessen Größe kleiner oder gleich der der Quelle ist.

case up

Runden Sie auf den nächsten zulässigen Wert, der größer oder gleich der Quelle ist.

Wir verwenden ähnliche Beispiele wie die aus @ Suragchs hervorragender Antwort , um diese verschiedenen Rundungsoptionen in der Praxis zu zeigen.

.awayFromZero

Auf den nächsten zulässigen Wert runden, dessen Größe größer oder gleich der der Quelle ist; keine direkte unter den C - Funktionen äquivalent, da diese Anwendungen, bedingt auf Zeichen von self, ceiloder floor, für positive und negative Werte selfdargestellt.

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

Entspricht der C- floorFunktion.

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

Entspricht der C- roundFunktion.

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

Diese Rundungsregel kann auch über die Null - Argument aufgerufen wird rounded()Methode .

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

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

.toNearestOrEven

Auf den nächsten zulässigen Wert runden; Wenn zwei Werte gleich nahe beieinander liegen, wird der gerade gewählt. äquivalent zur C-Funktion rint(/ sehr ähnlich zu 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

Entspricht der C- truncFunktion.

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

Wenn der Zweck der Rundung darin besteht, die Arbeit mit einer Ganzzahl vorzubereiten (z. B. Verwendung Intdurch FloatPointInitialisierung nach dem Runden), können wir einfach die Tatsache nutzen, dass beim Initialisieren einer IntVerwendung einer Double(oder Floatusw.) der Dezimalteil abgeschnitten wird.

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

Entspricht der C- ceilFunktion.

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

Nachtrag: Besuchen Sie den Quellcode, um FloatingPointzu überprüfen, ob die C-Funktionen den verschiedenen FloatingPointRoundingRuleRegeln entsprechen

Wenn wir möchten, können wir uns den Quellcode für das FloatingPointProtokoll ansehen, um die C-Funktion zu sehen, die den öffentlichen FloatingPointRoundingRuleRegeln entspricht.

Aus swift / stdlib / public / core / FloatingPoint.swift.gyb sehen wir, dass die Standardimplementierung der rounded(_:)Methode uns zur mutierenden round(_:)Methode macht:

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

Aus swift / stdlib / public / core / FloatingPointTypes.swift.gyb finden wir die Standardimplementierung von round(_:), in der die Äquivalenz zwischen den FloatingPointRoundingRuleRegeln und den C-Rundungsfunktionen offensichtlich ist:

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
quelle
@iosMentalist danke für die Aufforderung, ich habe den Titel der Antwort aktualisiert.
dfri
Wenn ich eine Gleichung wie 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
quelle
6

Swift 3: Wenn Sie auf eine bestimmte Ziffer runden möchten, z. B. 5.678434 -> 5.68, können Sie einfach die Funktion round () oder roundf () mit einer Multiplikation kombinieren:

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

Sie können FloatingPoint in Swift 3 auch wie folgt erweitern:

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
quelle
Können Sie das bitte erklären? Was Selfbedeutet das?
JZAU
@Jacky Self bezieht sich auf die Klasse FloatingPoint, während self auf die Instanz dieser Klasse verweist.
George Yacoub
@ GeorgeYacoub Self bezieht sich auf den Typ, der FloatingPoint entspricht, der erweitert wird (in diesem Beispiel wird ein Double verwendet), aber es handelt sich um Strukturen, nicht um Klassen
Leo Dabus
2

Swift 3

var myNum = 8.09
myNum.rounded() // result = 8 and leaves myNum unmodified
Dattatray Deokar
quelle
Nett. Ich wusste vorher nichts davon. Ein Hinweis: myNum.rounded()ändert sich nicht myNum, myNum.round()tut es aber .
Suragch
@ Suragch, ich habe die Antwort bearbeitet, um Ihren Kommentar wiederzugeben.
Adil Hussain
0

Möglicherweise möchten Sie auch überprüfen, ob das Double höher als der maximale Int-Wert ist, bevor Sie versuchen, den Wert in einen Int zu konvertieren.

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

Eine sehr einfache Lösung hat für mich funktioniert:

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

Nummer enthält Wert 2

Nazar Medeiros
quelle