如何快速将Double舍入到最接近的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
}

但到目前为止我一直做不到。

编辑 我有点是这样的:

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必须成为变量并在整个程序中进行更改(以便进行下一次计算),我不希望它发生。

Answers:


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)

四舍五入到小数点后两位:

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 Foundationimport Cocoaimport UIKit,所有这些最终都在内部导入达尔文)。
Mike S

54
还有lround()一个返回Int
Martin R

1
round()在小数位数> = .5时总是四舍五入,而在<.5(标准舍入)时总是四舍五入。” 除非不是这样。round(-16.5)返回-17,而不是-16。这是一个错误吗?
Daniel T.

1
@DanielT。-不是错误。四舍五入到最接近的较大负数。以这种方式思考,+ 16.5到+17距离零进一步移动了0.5。这意味着-16.5到-17距离零还远0.5。小区将是相反的,16.5至16为0.5更接近零,并-16.5至-16也是0.5更接近零
adougies

139

要将double舍入到最接近的整数,只需使用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数学函数一样roundlroundfloor,和ceil。但是,既然Swift内置了此功能,我将不再建议使用这些功能。感谢@dfri向我指出这一点。在此处查看@dfri的出色答案。我也做了类似的事情四舍五入CGFloat

Int(myDouble.rounded())<---如果双精度数不适合Int,这实际上可能会引发异常
Toad

@Toad,确定吗?我没有在文档中看到。
Suragch

我只是通过这个确切的问题解决了生产中的崩溃问题。但是,即使我错了,它不会崩溃,那么它仍然还是会给双打意外的结果> MAXINT
蟾蜍

1
@Toad,对,很好,谢谢。我在答案中添加了注释。
Suragch

83

Swift 3和4-使用协议中设计的rounded(_:)方法FloatingPoint

FloatingPoint协议(到其例如DoubleFloat符合)蓝图rounded(_:)方法

func rounded(_ rule: FloatingPointRoundingRule) -> Self

FloatingPointRoundingRule枚举在哪里枚举许多不同的舍入规则:

case awayFromZero

四舍五入到其幅度大于或等于源的幅度的最接近的允许值。

case down

四舍五入为小于或等于源的最接近的允许值。

case toNearestOrAwayFromZero

四舍五入到最接近的允许值;如果两个值相等,则选择一个较大的值。

case toNearestOrEven

四舍五入到最接近的允许值;如果两个值相等接近,则选择偶数。

case towardZero

四舍五入到其大小小于或等于源的大小的最接近的允许值。

case up

舍入到大于或等于源的最接近的允许值。

我们使用与@Suragch出色答案中的示例相似的示例,以实际展示这些不同的舍入选项。

.awayFromZero

四舍五入到大于或等于源的最大允许值;因此,C函数之间没有直接等价的关系,分别使用selfceil或的符号分别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协议的源代码,以直接查看与公共FloatingPointRoundingRule规则等效的C函数。

swift / stdlib / public / core / FloatingPoint.swift.gyb中,我们看到该方法的默认实现rounded(_:)使我们有了mutating 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

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

您还可以按以下方式在Swift 3中扩展FloatingPoint:

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),但它们是结构而不是类
Leo Dabus

2

迅捷3

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

真好 我以前不知道这个。注意事项:myNum.rounded()不会改变myNum,但是myNum.round()会改变。
Suragch '16

@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())
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.