我意识到Swift书籍提供了一个随机数生成器的实现。复制和粘贴这个实现是最佳实践吗?或者有没有这样的库,我们现在就可以使用?


当前回答

例如10(0-9)之间的随机数;

import UIKit

let randomNumber = Int(arc4random_uniform(10))

非常简单的代码-简单和简短。

其他回答

对于0到n-1之间的随机整数,使用arc4random_uniform(n)。

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

将结果转换为Int,这样你就不必显式地将你的vars类型为UInt32(这看起来不像swifty)。

我已经能够使用rand()来获得一个随机的CInt。你可以使用这样的方法使它成为Int型:

let myVar: Int = Int(rand())

你可以使用你最喜欢的C随机函数,并在需要时将值转换为Int。

使用arc4random_uniform ()

用法:

arc4random_uniform(someNumber: UInt32) -> UInt32

这将为您提供0到someNumber - 1范围内的随机整数。

UInt32的最大值为4,294,967,295(即2^32 - 1)。

例子:

抛硬币 让flip = arc4random_uniform(2) // 0或1 骰子滚 Let roll = arc4random_uniform(6) + 1 // 1 十月的任意一天 Let day = arc4random_uniform(31) + 1 // 1 90年代的任意一年 Let year = 1990 + arc4random_uniform(10)

一般形式:

let number = min + arc4random_uniform(max - min + 1)

其中number、max、min为UInt32。

是什么……

arc4random ()

你也可以通过使用arc4random()得到一个随机数,它会产生一个在0到2^32-1之间的UInt32。因此,要得到一个介于0和x-1之间的随机数,可以将其除以x并取余数。或者换句话说,使用余数运算符(%):

let number = arc4random() % 5 // 0...4

然而,这会产生轻微的模数偏差(参见这里和这里),所以这就是为什么建议使用arc4random_uniform()。

从Int转换到Int

通常情况下,为了在Int和UInt32之间来回转换,这样做是很好的:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

但问题是,Int的范围是-2,147,483,648…2,147,483,647在32位系统和范围-9,223,372,036,854,775,808…9223,372,036,854,775,807在64位系统上。将其与0…4,294,967,295的UInt32范围进行比较。U (UInt32)表示无符号。

考虑以下错误:

UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error

所以你只需要确保你的输入参数是在UInt32范围内,你不需要输出是在这个范围之外。

下面的代码将产生一个0到255之间的安全随机数:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

你这样称呼它:

print(UInt8.random)

对于更大的数字,它会变得更复杂。 这是我能想到的最好的:

extension UInt16 {
  public static var random: UInt16 {
    let count = Int(UInt8.random % 2) + 1
    var numbers = [UInt8](repeating: 0, count: 2)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt16($1) }
  }
}

extension UInt32 {
  public static var random: UInt32 {
    let count = Int(UInt8.random % 4) + 1
    var numbers = [UInt8](repeating: 0, count: 4)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt32($1) }
  }
}

这些方法使用一个额外的随机数来确定有多少uint8将被用于创建随机数。最后一行将[UInt8]转换为UInt16或UInt32。

我不知道后两个是否还算真正的随机,但你可以根据自己的喜好进行调整:)

这里有一个库可以很好地完成这项工作 https://github.com/thellimist/SwiftRandom

public extension Int {
    /// SwiftRandom extension
    public static func random(lower: Int = 0, _ upper: Int = 100) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }
}

public extension Double {
    /// SwiftRandom extension
    public static func random(lower: Double = 0, _ upper: Double = 100) -> Double {
        return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension Float {
    /// SwiftRandom extension
    public static func random(lower: Float = 0, _ upper: Float = 100) -> Float {
        return (Float(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension CGFloat {
    /// SwiftRandom extension
    public static func random(lower: CGFloat = 0, _ upper: CGFloat = 1) -> CGFloat {
        return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (upper - lower) + lower
    }
}