Як швидко обвести дубль до найближчого Int?


170

Я намагаюся зробити калькулятор швидкості зростання ( Double), який округлятиме результат до найближчого цілого числа і перераховує звідти, як такий:

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
}

але я поки що не міг.

EDIT Я якось робив це так:

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
}

Хоча я не заперечую, що це завжди округлення вниз, мені це не подобається, тому що firstUsersдовелося стати змінною і змінюватися протягом усієї програми (щоб зробити наступний розрахунок), чого я не хочу, щоб це сталося.

Відповіді:


253

У бібліотеці є roundдоступна інформація (вона насправді є , але імпорт та більшу частину часу ви хочете використовувати замість прямого використання ) .FoundationDarwinFoundationDarwinFoundationDarwin

import Foundation

users = round(users)

Запуск коду на ігровому майданчику, а потім дзвінок:

print(round(users))

Виходи:

15,0

round()завжди округляється вгору, коли знаходиться десятковий знак, >= .5і вниз, коли він < .5(стандартне округлення). Ви можете використовувати floor()для примусового округлення вниз і ceil()для примусового округлення.

Якщо вам необхідно округляти в певне місце, то помножте pow(10.0, number of places), roundі потім розділити на pow(10, number of places):

Округніть до 2 знаків після коми:

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

Виходи:

10.12

Примітка: Завдяки тому, як працює математика з плаваючою комою, roundedне завжди може бути абсолютно точно. Краще думати про це більше, ніж наближення округлення. Якщо ви робите це для цілей відображення, для форматування числа краще використовувати форматування рядків, а не використовувати математику для його округлення.


Хм, pow()на жаль, немає на дитячому майданчику
MrBr

1
@MrBr, pow()визначено в бібліотеці Дарвіна, тому вам потрібно import Darwinспочатку (або import Foundationабо import Cocoaабо import UIKitвсе це в кінці імпортувати Дарвін внутрішньо).
Майк S

54
Є також, lround()який повертає Int.
Мартін Р

1
" round()завжди округляється, коли десяткове місце становить> = .5 і вниз, коли він <.5 (стандартне округлення)." За винятком випадків, коли цього немає. round(-16.5)повертає -17, а не -16. Це помилка?
Даніель Т.

1
@DanielT. - не помилка. Це округлення до найближчого більшого від’ємного числа. Подумайте про це так: +16,5 до +17 рухається на 0,5 далі від нуля. Це означає, що від -16,5 до -17 також знаходиться на 0,5 далі від нуля. Стеля буде протилежною, +16,5 до +16 на 0,5 ближче до нуля, а -16,5 до -16 також на 0,5 ближче до нуля
adougies

139

Щоб округнути подвійне до найближчого цілого числа, просто використовуйте round().

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

Якщо ви не хочете змінювати початкове значення, скористайтеся rounded():

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

Як можна було очікувати ( а може і ні ), число на зразок 3.5округлене, а число як -3.5округлене вниз. Якщо вам потрібна інша поведінка округлення, ніж це, ви можете скористатися одним із правил округлення . Наприклад:

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

Якщо вам потрібен фактичний, Intтоді просто перекиньте його на один (але лише якщо ви впевнені, що подвійний не буде більшим за Int.max):

let myInt = Int(myDouble.rounded())

Примітки

  • Ця відповідь повністю переписана. Мій старий відповідь мав справу з C математичні функції , такі як round, lround, floorі ceil. Однак тепер, коли у Swift вбудована ця функціональність, я більше не можу рекомендувати використовувати ці функції. Дякую @dfri за те, що мені це вказали. Ознайомтеся з чудовою відповіддю @ dfri тут . Я також зробив щось подібне для округлення aCGFloat .

Int (myDouble.rounded ()) <--- це може насправді кинути виняток, якщо дубль не підходить до Int
Toad

@Toad, ви впевнені? Я цього не бачу в документації .
Сурагч

Я просто вирішив крах у виробництві саме цим питанням. Але навіть якщо я помилявся і він не зазнав краху, то все одно це дасть несподівані результати для парних> maxint
жаба

1
@Toad, правильно, хороший момент, дякую. Я додав записку до відповіді.
Сурагч

85

Swift 3 і 4 - використання rounded(_:)методу, як зображено на малюнку в FloatingPointпротоколі

FloatingPointПротокол (наприклад , до якого Doubleі FloatВідповідність нормам) креслення в rounded(_:)метод

func rounded(_ rule: FloatingPointRoundingRule) -> Self

Де FloatingPointRoundingRuleє перелік, що перераховує ряд різних правил округлення:

case awayFromZero

Закруглете до найближчого дозволеного значення, величина якого більше або дорівнює величині джерела.

case down

Закруглете до найближчого дозволеного значення, яке менше або рівне джерелу.

case toNearestOrAwayFromZero

Округніть до найближчого дозволеного значення; якщо два значення однаково близькі, вибирається одне з більшою величиною.

case toNearestOrEven

Округніть до найближчого дозволеного значення; якщо два значення однаково близькі, вибирається рівне.

case towardZero

Закруглете до найближчого дозволеного значення, величина якого менша або дорівнює величині джерела.

case up

Закруглете до найближчого дозволеного значення, яке більше або рівне джерелу.

Ми використовуємо подібні приклади до прикладів із відмінної відповіді @ Suragch, щоб показати ці різні варіанти округлення на практиці.

.awayFromZero

Закруглете до найближчого дозволеного значення, величина якого більше або дорівнює величині джерела; немає прямого еквівалента серед функцій C, так як це використовує, умовно на знаку self, ceilабо floor, для позитивних і негативних значень self, відповідно.

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

Еквівалентна floorфункції С.

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

Еквівалентна 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

До цього правила округлення також можна отримати доступ, використовуючи rounded()метод нульового аргументу .

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

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

.toNearestOrEven

Округніть до найближчого дозволеного значення; якщо два значення однаково близькі, вибирається рівне; еквівалент функції C rint(/ дуже схожа на 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

Еквівалентна 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

Якщо метою округлення є підготовка до роботи з цілим числом (наприклад, використання Intшляхом FloatPointініціалізації після округлення), ми можемо просто використати той факт, що при ініціалізації Intвикористання Double(або Floatтощо) десяткова частина буде відсічена.

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

Еквівалентна 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

Додаток: відвідування вихідного коду для FloatingPointперевірки відповідності функцій C різним FloatingPointRoundingRuleправилам

Якщо ми хочемо, ми можемо подивитися на вихідний код FloatingPointпротоколу, щоб безпосередньо побачити еквіваленти функції C загальнодоступним FloatingPointRoundingRuleправилам.

З swift / stdlib / public / core / FloatingPoint.swift.gyb ми бачимо, що реалізація rounded(_:)методу за замовчуванням робить нас round(_:)методом мутації :

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

З swift / stdlib / public / core / FloatingPointTypes.swift.gyb ми знаходимо реалізацію за замовчуванням round(_:), в якій FloatingPointRoundingRuleочевидна еквівалентність правил і функцій округлення 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 дякую за підказку, я оновив заголовок відповіді.
dfri

Якщо я хочу будь-яке рівняння, наприклад, 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: Якщо ви хочете округлити певне цифрне число, наприклад 5.678434 -> 5.68, ви можете просто поєднати функцію round () або roundf () з множенням:

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

4

Ви також можете розширити FloatingPoint у Swift 3, як описано нижче:

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

    }
}

324.0.rounded(to: 5)   // 325

Чи можете ви поясніть це? Що Selfозначає?
JZAU

@Jacky Self посилається на клас FloatingPoint, тоді як self посилається на екземпляр цього класу.
Джордж Якуб

@GeorgeYacoub Self позначає тип, який відповідає FloatingPoint, який розширюється (у цьому зразку використання є подвійним), але вони є структурами, а не класами
Лео Дабус

2

Швидкий 3

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

Приємно. Я про це раніше не знав. Одна примітка: myNum.rounded()не змінюється myNum, а myNum.round()робить.
Сурагч

@Suragch, я відредагував відповідь, щоб відобразити ваш коментар.
Аділ Хуссейн

0

Ви також можете перевірити, чи подвоєння вище максимального значення Int, перш ніж спробувати перетворити значення в Int.

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

-1

Для мене спрацювало дуже просте рішення:

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

число містить значення 2

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.