提问者:小点点

如何在Swift中生成一个随机数?


我意识到Swift的书提供了一个随机数生成器的实现。复制和粘贴此实现是最佳做法吗?或者是否有一个图书馆可以做到这一点,我们现在可以使用?


共3个答案

匿名用户

Swift 4.2

Xcode 10附带的Swift 4.2为许多数据类型引入了新的易于使用的随机函数。可以对数值类型调用< code>random()方法。

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()

匿名用户

使用arc4random_uniform(n)表示0到n-1之间的随机整数。

let diceRoll = Int(arc4random_uniform(6) + 1)

将结果转换为Int,这样就不必将变量显式地输入为< code>UInt32(这似乎不太方便)。

匿名用户

编辑:针对Swift 3.0更新

arc4random在Swift中运行良好,但基本函数仅限于32位整数类型(Int是iPhone 5S和现代Mac上的64位)。下面是一个泛型函数,用于一个可由整数文字表示的随机数类型:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

我们可以使用这个新的泛型函数来扩展UInt64,添加边界参数并减轻模偏差。(这是从arc4random.c直接提起的)

public extension UInt64 {
    public static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
        var m: UInt64
        let u = upper - lower
        var r = arc4random(UInt64.self)

        if u > UInt64(Int64.max) {
            m = 1 + ~u
        } else {
            m = ((max - (u * 2)) + 1) % u
        }

        while r < m {
            r = arc4random(UInt64.self)
        }

        return (r % u) + lower
    }
}

有了它,我们可以为相同的参数扩展 Int64,处理溢出:

public extension Int64 {
    public static func random(lower: Int64 = min, upper: Int64 = max) -> Int64 {
        let (s, overflow) = Int64.subtractWithOverflow(upper, lower)
        let u = overflow ? UInt64.max - UInt64(~s) : UInt64(s)
        let r = UInt64.random(upper: u)

        if r > UInt64(Int64.max)  {
            return Int64(r - (UInt64(~lower) + 1))
        } else {
            return Int64(r) + lower
        }
    }
}

为了完成家庭...

private let _wordSize = __WORDSIZE

public extension UInt32 {
    public static func random(lower: UInt32 = min, upper: UInt32 = max) -> UInt32 {
        return arc4random_uniform(upper - lower) + lower
    }
}

public extension Int32 {
    public static func random(lower: Int32 = min, upper: Int32 = max) -> Int32 {
        let r = arc4random_uniform(UInt32(Int64(upper) - Int64(lower)))
        return Int32(Int64(r) + Int64(lower))
    }
}

public extension UInt {
    public static func random(lower: UInt = min, upper: UInt = max) -> UInt {
        switch (_wordSize) {
            case 32: return UInt(UInt32.random(UInt32(lower), upper: UInt32(upper)))
            case 64: return UInt(UInt64.random(UInt64(lower), upper: UInt64(upper)))
            default: return lower
        }
    }
}

public extension Int {
    public static func random(lower: Int = min, upper: Int = max) -> Int {
        switch (_wordSize) {
            case 32: return Int(Int32.random(Int32(lower), upper: Int32(upper)))
            case 64: return Int(Int64.random(Int64(lower), upper: Int64(upper)))
            default: return lower
        }
    }
}

毕竟,我们终于可以这样做了:

let diceRoll = UInt64.random(lower: 1, upper: 7)