在Swift中生成指定范围内的随机整数最简单的方法是什么?

22

我迄今为止想出的方法是这样的:

func randRange (lower : Int , upper : Int) -> Int {
    let difference = upper - lower
    return Int(Float(rand())/Float(RAND_MAX) * Float(difference + 1)) + lower
}

这将生成包括上限和下限在内的随机整数。


这对我来说看起来相当容易。问题是什么? - Luke
2
卢克,我只是想知道Swift内部或外部是否有一些功能可以让它更紧凑或更可靠。我认为下面的回答已经很清楚地表明了有这样的功能。 - RonH
好的,我还没有真正地机会去适应它。 - Luke
1
没有内置这个功能,这不是相当糟糕吗? - Alper
让我们以一个例子开始,其中“范围”具有“最小值”和“最大值”(均为Uint32) - let random = arc4random_uniform(max - min + 1) + min。如有需要,可以将其扩展到生成随机负数的概念。 - holex
4个回答

51

这是一个更加简单易懂的版本:

func randRange (lower: Int , upper: Int) -> Int {
    return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
}

这可以进一步简化,如果您决定此函数仅适用于无符号值:
func randRange (lower: UInt32 , upper: UInt32) -> UInt32 {
    return lower + arc4random_uniform(upper - lower + 1)
}

或者,按照安东(+1 给你)提出的优秀想法,使用范围作为参数:

func random(range: Range<UInt32>) -> UInt32 {
    return range.startIndex + arc4random_uniform(range.endIndex - range.startIndex + 1)
}

谢谢,Jean - 很高兴知道我可以简单地引入arc4random。我还没有足够的声望给你投票,但是! - RonH
@RonH 嘿,没问题 Ron,这都是为了好玩 :) - Jean Le Moignan
如何生成一个介于上限和下限之间的随机浮点数? - fabian

14

根据评论的建议,已经编辑以消除取模偏差。 (感谢!)

我认为一个不错的方法是使用Swift的Range来定义边界,因为这样你可以指定1..100或1...100(包括或排除上限)。到目前为止,我想到的最好的方法是:

import Foundation // needed for rand()

func randInRange(range: Range<Int>) -> Int {
    // arc4random_uniform(_: UInt32) returns UInt32, so it needs explicit type conversion to Int
    // note that the random number is unsigned so we don't have to worry that the modulo
    // operation can have a negative output
    return  Int(arc4random_uniform(UInt32(range.endIndex - range.startIndex))) + range.startIndex
}

// generate 10 random numbers between -1000 and 999
for _ in 0...100 {
    randInRange(-1000...1000)
}

我尝试在Range上使用扩展,但似乎无法专门扩展Range< T where T: Int >。如果能够获得类似于(1..100).rand()的语法,那就更好了。


2
“模数偏差”是一个众所周知的结果:在大多数情况下,使用模算术会产生非均匀的结果。 - pjs
谢谢,安东 - 使用范围函数很好 - 但是,我更喜欢简的解决方案的视觉简洁性。 - RonH
目前(在Xcode 6 beta 5上),这不会生成-1000到999之间的范围,正如注释所说,而是会生成-1000到1000之间的范围。 range.endIndex的值对应于a ..< range边界的值(即排除边界)。因此+1是不必要的。Jean上面的版本显然也有同样的问题。我不明白的是为什么他们会使用排除边界,对于一个叫做endIndex的属性来说似乎很反直觉...也许在beta 6中已经改变了? - iOS Gamer

6

这可以在最新的Swift版本中完成:

Int.random(in: 1...99)

以上代码将会生成一个介于1和99之间的随机整数(包括99)。


2
如果您喜欢使用扩展程序:
extension CountableClosedRange where Bound == Int {
    var randomValue: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

extension CountableRange where Bound == Int {
    var randomValue: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

(0...6).randomValue
(0..<7).randomValue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接