如何快速将 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(例如Double
和Float
符合)蓝图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 函数之间没有直接等效项,因为它使用 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()
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 数学函数,例如round
、lround
、floor
和 ceil
。但是,既然 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()
总是在小数位为 >= .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, 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?的主要内容,如果未能解决你的问题,请参考以下文章