Jak szybko zaokrąglić Double do najbliższego Int?


170

Próbuję zrobić kalkulator tempa wzrostu ( Double), który zaokrągli wynik do najbliższej liczby całkowitej i ponownie obliczy od tego miejsca, jako taki:

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
}

ale jak dotąd nie mogłem.

EDYCJA Zrobiłem to tak:

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
}

Chociaż nie przeszkadza mi to, że zawsze zaokrągla się w dół, nie podoba mi się to, ponieważ firstUsersmusiałem stać się zmienną i zmieniać w całym programie (aby wykonać następne obliczenia), czego nie chcę, aby tak się stało.

Odpowiedzi:


253

W bibliotece jest rounddostępny (w rzeczywistości jest w , ale importuje i przez większość czasu będziesz chciał używać zamiast bezpośrednio) .FoundationDarwinFoundationDarwinFoundationDarwin

import Foundation

users = round(users)

Uruchomienie kodu na placu zabaw, a następnie wywołanie:

print(round(users))

Wyjścia:

15.0

round()zawsze zaokrągla w górę, gdy miejsce dziesiętne wynosi, >= .5aw dół, gdy jest < .5(zaokrąglanie standardowe). Możesz użyć floor()do wymuszenia zaokrąglenia w dół i ceil()do wymuszenia zaokrąglenia w górę.

Jeśli trzeba rundzie do określonego miejsca, a następnie pomnożyć przez pow(10.0, number of places), rounda następnie podzielić przez pow(10, number of places):

Zaokrąglij do 2 miejsc po przecinku:

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

Wyjścia:

10.12

Uwaga: Ze względu na sposób działania matematyki zmiennoprzecinkowej roundedmoże nie zawsze być idealnie dokładne. Najlepiej myśleć o tym bardziej jako o przybliżeniu zaokrąglania. Jeśli robisz to do celów wyświetlania, lepiej jest użyć formatowania ciągów do sformatowania liczby, zamiast używać matematyki do jej zaokrąglania.


Hmm pow()niestety nie jest dostępny na placu zabaw
MrBr

1
@MrBr, pow()jest zdefiniowane w bibliotece Darwina, więc musisz import Darwinnajpierw (lub import Foundationlub import Cocoalub import UIKit, z których wszystkie kończą się wewnętrznym importem Darwina).
Mike S

54
Istnieje również, lround()który zwraca Int.
Martin R

1
round()zawsze zaokrągla w górę, gdy miejsce dziesiętne to> = 0,5, i w dół, gdy wynosi <0,5 (zaokrąglanie standardowe).” Chyba że tak nie jest. round(-16.5)zwraca -17, a nie -16. Czy to błąd?
Daniel T.

1
@DanielT. - to nie błąd. Zaokrągla w górę do najbliższej większej liczby ujemnej. Pomyśl o tym w ten sposób, +16,5 do +17 przesuwa się o 0,5 dalej od zera. Oznacza to, że od -16,5 do -17 jest również o 0,5 dalej od zera. Ceil byłby odwrotny, +16,5 do +16 to 0,5 bliżej zera, a -16,5 do -16 to również 0,5 bliżej zera
adougies

139

Aby zaokrąglić podwójną do najbliższej liczby całkowitej, po prostu użyj round().

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

Jeśli nie chcesz modyfikować oryginalnej wartości, użyj rounded():

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

Jak można by się spodziewać ( lub nie ), liczba taka jak 3.5jest zaokrąglana w górę, a liczba podobna -3.5jest zaokrąglana w dół. Jeśli potrzebujesz innego sposobu zaokrąglania, możesz użyć jednej z reguł zaokrąglania . Na przykład:

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

Jeśli potrzebujesz rzeczywistego, Intpo prostu rzuć go na jeden (ale tylko wtedy, gdy masz pewność, że Double nie będzie większy niż Int.max):

let myInt = Int(myDouble.rounded())

Uwagi

  • Ta odpowiedź została całkowicie przepisana. Mój stary odpowiedź rozpatrywane C funkcje matematyczne podoba round, lround, floor, i ceil. Jednak teraz, gdy Swift ma wbudowaną tę funkcję, nie mogę już zalecać korzystania z tych funkcji. Dziękuję @dfri za wskazanie mi tego. Sprawdź doskonałą odpowiedź @ dfri tutaj . Zrobiłem też coś podobnego do zaokrąglaniaCGFloat .

Int (myDouble.rounded ()) <--- to może faktycznie zgłosić wyjątek, jeśli double nie pasuje do Int
Toad

@Toad, czy na pewno? Nie widzę tego w dokumentacji .
Suragch

Właśnie rozwiązałem awarię podczas produkcji z tym właśnie problemem. Ale nawet gdybym się mylił i się nie wywalił, to i tak dałoby to nieoczekiwane rezultaty dla deblów> maxint
Toad

1
@Toad, racja, słuszna uwaga, dzięki. Dodałem notatkę do odpowiedzi.
Suragch

83

Swift 3 i 4 - wykorzystując rounded(_:)metodę zgodnie ze schematem w FloatingPointprotokole

FloatingPointProtokół (w którym np Doublei FloatPrzylega) plany na rounded(_:)metodę

func rounded(_ rule: FloatingPointRoundingRule) -> Self

Gdzie FloatingPointRoundingRulejest wyliczenie wyliczające kilka różnych reguł zaokrąglania:

case awayFromZero

Zaokrąglij do najbliższej dozwolonej wartości, której wielkość jest większa lub równa wartości źródła.

case down

Zaokrąglij do najbliższej dozwolonej wartości, która jest mniejsza lub równa źródłu.

case toNearestOrAwayFromZero

Zaokrąglij do najbliższej dozwolonej wartości; jeśli dwie wartości są jednakowo bliskie, wybierana jest ta o większej wartości.

case toNearestOrEven

Zaokrąglij do najbliższej dozwolonej wartości; jeśli dwie wartości są jednakowo zbliżone, wybierana jest ta parzysta.

case towardZero

Zaokrąglij do najbliższej dozwolonej wartości, której wielkość jest mniejsza lub równa wartości źródła.

case up

Zaokrąglij do najbliższej dozwolonej wartości, która jest większa lub równa źródłu.

Korzystamy z przykładów podobnych do tych z doskonałej odpowiedzi @ Suragcha, aby pokazać te różne opcje zaokrąglania w praktyce.

.awayFromZero

Zaokrąglić do najbliższej dozwolonej wartości, której wielkość jest większa lub równa wartości źródła; Brak bezpośredniego odpowiednik wśród funkcji C, jak ta wykorzystuje, warunkowo na znak self, ceillub floor, dla dodatnich i ujemnych wartości self, odpowiednio.

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

Odpowiednik floorfunkcji 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

Odpowiednik roundfunkcji 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

Dostęp do tej reguły zaokrąglania można również uzyskać przy użyciu rounded()metody z zerowym argumentem .

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

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

.toNearestOrEven

Zaokrąglij do najbliższej dozwolonej wartości; jeśli dwie wartości są jednakowo bliskie, wybierana jest parzysta; odpowiednik funkcji C rint(/ bardzo podobny do 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

Odpowiednik truncfunkcji 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

Jeśli celem zaokrąglania jest przygotowanie do pracy z liczbą całkowitą (np. Użycie Intprzez FloatPointinicjalizację po zaokrągleniu), możemy po prostu skorzystać z faktu, że podczas inicjalizacji za Intpomocą a Double(lub Floatitp.) Część dziesiętna zostanie obcięta.

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

Odpowiednik ceilfunkcji 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

Dodatek: odwiedzenie kodu źródłowego w FloatingPointcelu sprawdzenia równoważności funkcji C z różnymi FloatingPointRoundingRuleregułami

Jeśli chcemy, możemy spojrzeć na kod źródłowy FloatingPointprotokołu, aby bezpośrednio zobaczyć odpowiedniki funkcji C dla FloatingPointRoundingRulereguł publicznych .

Ze swift / stdlib / public / core / FloatingPoint.swift.gyb widzimy, że domyślna implementacja rounded(_:)metody czyni nas round(_:)metodą mutującą :

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

Ze swift / stdlib / public / core / FloatingPointTypes.swift.gyb znajdujemy domyślną implementację round(_:), w której FloatingPointRoundingRulewidoczna jest równoważność między regułami a funkcjami zaokrąglającymi w 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 dzięki za podpowiedź, zaktualizowałem tytuł odpowiedzi.
dfri

Jeśli chcę takie równanie, jak 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: Jeśli chcesz zaokrąglić do określonej liczby cyfr, np. 5,678434 -> 5,68, możesz po prostu połączyć funkcję round () lub roundf () z mnożeniem:

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

4

Możesz również przedłużyć FloatingPoint w Swift 3 w następujący sposób:

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

    }
}

324.0.rounded(to: 5)   // 325

Czy możesz to wyjaśnić? Co to Selfznaczy?
JZAU,

@Jacky Self odnosi się do klasy FloatingPoint, podczas gdy self odnosi się do instancji tej klasy.
George Yacoub,

@GeorgeYacoub Self odnosi się do typu zgodnego z rozszerzanym FloatingPoint (w tym przypadku użycie próbki to Double), ale są to struktury, a nie klasy
Leo Dabus

2

Szybki 3

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

Miły. Nie wiedziałem o tym wcześniej. Jedna uwaga: myNum.rounded()nie zmienia się myNum, ale myNum.round()zmienia.
Suragch

@Suragch, zredagowałem odpowiedź, aby odzwierciedlić Twój komentarz.
Adil Hussain

0

Możesz również chcieć sprawdzić, czy wartość double jest wyższa niż maksymalna wartość Int, zanim spróbujesz przekonwertować wartość na Int.

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

-1

U mnie zadziałało bardzo proste rozwiązanie:

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

liczba zawiera wartość 2

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.