如何快速将 Double 舍入到最近的 Int?

Posted

技术标签:

【中文标题】如何快速将 Double 舍入到最近的 Int?【英文标题】:How to round a Double to the nearest Int in swift? 【发布时间】:2014-12-08 15:59:51 【问题描述】:

我正在尝试制作一个增长率计算器 (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 必须成为一个变量并在整个程序中进行更改(以便进行下一次计算),我不这样做'不希望它发生。

【问题讨论】:

【参考方案1】:

斯威夫特 3: 如果您想四舍五入到某个数字,例如5.678434 -> 5.68 你可以将 round() 或 roundf() 函数与乘法相结合:

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

【讨论】:

【参考方案2】:

在尝试将值转换为 Int 之前,您可能还想检查双精度值是否高于最大 Int 值。

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

【讨论】:

【参考方案3】:

Swift 3 和 4 - 使用 rounded(_:) 方法,如 FloatingPoint 协议中的蓝图

FloatingPoint protocol(例如DoubleFloat 符合)蓝图rounded(_:) method

func rounded(_ rule: FloatingPointRoundingRule) -> Self

其中FloatingPointRoundingRule 是枚举多个不同舍入规则的枚举:

case awayFromZero

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

case down

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

case toNearestOrAwayFromZero

四舍五入到最接近的允许值;如果两个值同样接近, 选择幅度更大的那个。

case toNearestOrEven

四舍五入到最接近的允许值;如果两个值同样接近, 偶数被选中。

case towardZero

四舍五入到最接近的允许值,其幅度小于或 与源的相同。

case up

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

我们使用与@Suragch's excellent answer 中的示例类似的示例来在实践中展示这些不同的舍入选项。

.awayFromZero

四舍五入到最接近的允许值,其幅度大于或等于源的幅度; C 函数之间没有直接等效项,因为它使用 selfceilfloor 的符号,分别对应 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() method 访问此舍入规则。

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 by FloatPoint 初始化),我们可以简单地利用这样一个事实,即在初始化Int 时使用@ 987654366@(或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(_:) 方法的默认实现使我们使用了变异的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 感谢您的提示,我已经更新了答案的标题。 如果我想要任何等式,例如 3.0 = 3、3.1 = 3.5、3.4 = 3.5、3.6 = 4、3.9 - 4【参考方案4】:

斯威夫特 3

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

【讨论】:

不错。我以前不知道这个。注意:myNum.rounded() 不会改变 myNum,但 myNum.round() 会。 @Suragch,我已经编辑了答案以反映您的评论。【参考方案5】:

一个非常简单的解决方案对我有用:

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

数字包含值 2

【讨论】:

使用floatValue.rounded()默认函数。【参考方案6】:

您还可以在 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 是什么意思? @Jacky Self 指的是 FloatingPoint 类,而 self 指的是该类的实例。 @GeorgeYacoub Self 指的是符合正在扩展的 FloatingPoint 的类型(在示例中使用的是 Double),但它们是结构,而不是类【参考方案7】:

要将双精度数四舍五入到最接近的整数,只需使用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

正如人们所期望的 (or might not),像 3.5 这样的数字会向上取整,而像 -3.5 这样的数字会向下取整。如果您需要不同的舍入行为,可以使用rounding rules 之一。例如:

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

如果您需要实际的 Int,则只需将其转换为 1(但前提是您确定 Double 不会大于 Int.max):

let myInt = Int(myDouble.rounded())

注意事项

此答案已完全重写。我的旧答案涉及 C 数学函数,例如 roundlroundfloorceil。但是,既然 Swift 已经内置了这个功能,我不再推荐使用这些功能。感谢@dfri 向我指出这一点。查看@dfri's excellent answer here。我也为rounding a CGFloat 做了类似的事情。

【讨论】:

Int(myDouble.rounded()) @Toad,你确定吗?我在documentation 中没有看到。 我刚刚用这个确切的问题解决了生产中的崩溃问题。但是即使我错了并且它不会崩溃,那么它仍然会给双打> maxint带来意想不到的结果 @Toad,对,好点,谢谢。我在答案中添加了注释。【参考方案8】:
**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

【讨论】:

【参考方案9】:

Foundation 库中有一个round 可用(它实际上在Darwin 中,但Foundation 导入Darwin 并且大多数时候你会想要使用Foundation直接使用Darwin

import Foundation

users = round(users)

在操场上运行您的代码,然后调用:

print(round(users))

输出:

15.0

round() 总是在小数位为 &gt;= .5 时向上舍入,在小数位为 &lt; .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, pow()是在Darwin库中定义的,所以你需要先import Darwin(或者import Foundation或者import Cocoa或者import UIKit,最后都是导入Darwin内部)。 还有lround(),它返回一个Int "round() 总是在小数位 >= .5 时向上取整,在 round(-16.5) 返回 -17,而不是 -16。这是一个错误吗? @DanielT。 - 不是错误。它四舍五入到最接近的较大负数。这样想,+16.5 到 +17 就是离零更远了 0.5。这意味着 -16.5 到 -17 也离零远了 0.5。 Ceil 则相反,+16.5 到 +16 是 0.5 接近于零,-16.5 到 -16 也是 0.5 接近于零

以上是关于如何快速将 Double 舍入到最近的 Int?的主要内容,如果未能解决你的问题,请参考以下文章

如何在小数点后将 Dart 中的双精度数舍入到给定的精度?

将 double 转换为 Int,向下舍入

如何将值向上舍入到一个数字的最接近的因子[重复]

将双精度数舍入到 x 有效数字

舍入到偶数131.575导致奇数而不是偶数

如何在 PHP 中舍入到最接近的 3 倍数? [复制]