Как быстро округлить Double до ближайшего Int?

Я пытаюсь сделать калькулятор скорости роста (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
}

но я пока не могу.

РЕДАКТИРОВАТЬ Я сделал это примерно так:

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 должен был стать переменной и изменяться на протяжении всей программы (для выполнения следующего вычисления), чего я не хочу, чтобы это произошло. .


person duarte harris    schedule 14.10.2014    source источник


Ответы (8)


В Foundation библиотеке есть round (на самом деле он находится в Darwin, но Foundation импортирует Darwin, и большую часть времени вы захотите использовать Foundation вместо прямого использования Darwin).

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 не всегда может быть совершенно точным. Лучше думать об этом как о приближении округления. Если вы делаете это для отображения, лучше использовать строковое форматирование для форматирования числа, а не математические вычисления для его округления.

person Mike S    schedule 14.10.2014
comment
Хм pow() к сожалению недоступен на детской площадке - person MrBr; 12.11.2015
comment
@MrBr, pow() определен в библиотеке Дарвина, поэтому вам нужно сначала import Darwin (или import Foundation, или import Cocoa, или import UIKit, все из которых в конечном итоге импортируют Дарвина внутри). - person Mike S; 12.11.2015
comment
Также есть lround(), который возвращает Int. - person Martin R; 02.04.2016
comment
round() всегда округляется в большую сторону, если десятичный разряд составляет ›= .5, и в меньшую сторону, когда он равен‹ .5 (стандартное округление). За исключением тех случаев, когда это не так. round(-16.5) возвращает -17, а не -16. Это ошибка? - person Daniel T.; 08.09.2017
comment
@DanielT. - не баг. Это округление до ближайшего большего отрицательного числа. Подумайте об этом так: от +16,5 до +17 уходит на 0,5 дальше от нуля. Это означает, что от -16,5 до -17 также на 0,5 дальше от нуля. Ceil будет противоположным, от +16,5 до +16 на 0,5 ближе к нулю, а от -16,5 до -16 также на 0,5 ближе к нулю. - person adougies; 21.10.2019

Чтобы округлить двойное до ближайшего целого числа, просто используйте 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, просто приведите его к единице (но только если вы уверены, что Double не будет больше, чем Int.max):

let myInt = Int(myDouble.rounded())

Примечания

  • Этот ответ полностью переписан. Мой старый ответ касался математических функций C, таких как round, lround, floor и ceil. Однако теперь, когда в Swift встроена эта функция, я больше не могу рекомендовать их использование. Спасибо @dfri за то, что указали мне на это. Ознакомьтесь с отличным ответом @dfri здесь. Я также сделал нечто подобное для округления CGFloat.
person Suragch    schedule 14.01.2016
comment
Int (myDouble.ounded ()) ‹--- это может фактически вызвать исключение, если double не подходит для Int - person Toad; 18.10.2018
comment
@ Жаба, ты уверен? Я не вижу этого в документации. - person Suragch; 18.10.2018
comment
Я только что решил сбой в производстве именно с этой проблемой. Но даже если бы я ошибся и он не вылетел, все равно он дал бы неожиданные результаты для удвоений ›maxint - person Toad; 19.10.2018
comment
@Toad, верно, хорошее замечание, спасибо. Я добавил примечание к ответу. - person Suragch; 19.10.2018

Swift 3 и 4 - использование метода rounded(_:), как это предусмотрено в протоколе FloatingPoint

_ 6_ метод

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

Эквивалентно функции C 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

Эквивалентно функции 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

К этому правилу округления также можно получить доступ с помощью 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

Эквивалентно функции 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

Если целью округления является подготовка к работе с целым числом (например, с использованием 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

Эквивалентно функции 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

Приложение: посещение исходного кода FloatingPoint для проверки эквивалентности функций C различным FloatingPointRoundingRule правилам.

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

Из public / stdd. FloatingPoint.swift.gyb мы видим, что реализация метода rounded(_:) по умолчанию делает нас мутирующим методом round(_:):

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

Из swift 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)
    }
}
person dfrib    schedule 05.01.2017
comment
@iosMentalist спасибо за подсказку, я обновил заголовок ответа. - person dfrib; 16.08.2018
comment
Если мне нужно какое-либо уравнение, например, 3,0 = 3, 3,1 = 3,5, 3,4 = 3,5, 3,6 = 4, 3,9 - 4 - person PJR; 10.10.2018

Swift 3: если вы хотите округлить до определенного числа, например 5.678434 -> 5.68 вы можете просто объединить функцию round () или roundf () с умножением:

let value:Float = 5.678434
let roundedValue = roundf(value * 100) / 100
print(roundedValue) //5.68
person Thoms    schedule 20.09.2017

Вы также можете расширить 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
person Leo Dabus    schedule 14.01.2017
comment
Не могли бы вы объяснить это? Что означает Self? - person JZAU; 07.06.2017
comment
@Jacky Self относится к классу FloatingPoint, тогда как self относится к экземпляру этого класса. - person George Yacoub; 05.08.2017
comment
@GeorgeYacoub Self относится к типу, который соответствует расширяемому FloatingPoint (в этом примере используется Double), но они являются структурами, а не классами. - person Leo Dabus; 30.06.2019

Swift 3

var myNum = 8.09
myNum.rounded() // result = 8 and leaves myNum unmodified
person Dattatray Deokar    schedule 29.12.2016
comment
Хороший. Я не знал об этом раньше. Одно примечание: myNum.rounded() не меняет myNum, но myNum.round() меняет. - person Suragch; 30.12.2016
comment
@Suragch, я отредактировал ответ, чтобы отразить ваш комментарий. - person Adil Hussain; 03.01.2020

У меня сработало очень простое решение:

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

число содержит значение 2

person Nazar Medeiros    schedule 27.11.2019

Вы также можете проверить, превышает ли значение double максимальное значение Int, прежде чем пытаться преобразовать значение в Int.

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