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

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
}

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

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

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все, что в конечном итоге приведет к внутреннему импорту Дарвина).
Майк С
54
Существует также, lround()который возвращает Int.
Мартин Р
1
round()msgstr " всегда округляется, когда десятичный разряд равен> = .5, и уменьшается, когда он <.5 (стандартное округление)." За исключением случаев, когда это не так. round(-16.5)возвращает -17, а не -16. Это ошибка?
Даниэль Т.
1
@DanielT. - не ошибка. Он округляется до ближайшего большего отрицательного числа. Подумайте об этом следующим образом: от +16,5 до +17 отодвигает 0,5 от нуля. Это означает, что от -16,5 до -17 также на 0,5 больше от нуля. Ceil будет противоположным, +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просто приведите его к одному (но только если вы уверены, что Double не будет больше Int.max):

let myInt = Int(myDouble.rounded())

Ноты

  • Этот ответ полностью переписан. Мой старый ответ имел дело с C математические функции , такие как round, lround, floorи ceil. Однако теперь, когда в Swift встроены эти функции, я больше не могу рекомендовать использовать эти функции. Спасибо @dfri за указание на это. Проверьте отличный ответ @ dfri здесь . Я также сделал нечто подобное для округленияCGFloat .
Suragch
источник
Int (myDouble.ounded ()) <--- это может на самом деле вызвать исключение, если double не соответствует Int
Toad
@ Дорогая, ты уверена? Я не вижу этого в документации .
Сурагч
Я только что решил проблему с производством именно с этой проблемой. Но даже если я ошибаюсь, и он не рухнет, он все равно даст неожиданные результаты для парных разрядов> maxint
Toad
1
@ Да, хорошо, хорошо, спасибо. Я добавил примечание к ответу.
Сурагч
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функции 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

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

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

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

Приложение: посещение исходного кода для 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)
    }
}
dfri
источник
@iosMentalist спасибо за приглашение, я обновил заголовок ответа.
dfri
Если я хочу какое-либо уравнение, например, 3,0 = 3, 3,1 = 3,5, 3,4 = 3,5, 3,6 = 4,
3,9-4
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, который расширяется (в этом примере используется Double), но это структуры, а не классы
Лев Дабус
2

Свифт 3

var myNum = 8.09
myNum.rounded() // result = 8 and leaves myNum unmodified
Дататрай Деокар
источник
Ницца. Я не знал об этом раньше. Одно замечание: myNum.rounded()не меняется myNum, но myNum.round()меняется.
Сурагч
@Suragch, я отредактировал ответ, чтобы отразить твой комментарий.
Адиль Хуссейн
0

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

let number = Double.infinity
if number >= Double(integerLiteral: Int64.max) {
  let rounded = Int.max
} else {
  let rounded = Int(number.rounded())
}
rockdaswift
источник
-1

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

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

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

Назар Медейрос
источник