我意识到Swift书籍提供了一个随机数生成器的实现。复制和粘贴这个实现是最佳实践吗?或者有没有这样的库,我们现在就可以使用?
当前回答
斯威夫特4.2
拜拜导入Foundation C库arc4random_uniform()
// 1
let digit = Int.random(in: 0..<10)
// 2
if let anotherDigit = (0..<10).randomElement() {
print(anotherDigit)
} else {
print("Empty range.")
}
// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
使用random(in:)从范围中生成随机数字。 randomElement()返回nil如果范围是空的,所以你打开返回的Int?用if let。 使用random(in:)生成随机Double、Float或CGFloat,使用random()返回随机Bool类型。
更多@官方
其他回答
编辑:为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)
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
从iOS 9开始,你可以使用新的GameplayKit类以各种方式生成随机数。
你有四种源类型可以选择:一般随机源(未命名,直到系统选择它做什么),线性同余,ARC4和梅森扭扭。它们可以生成随机int型、浮点型和bool型。
在最简单的层面上,你可以从系统内置的随机源生成一个随机数,如下所示:
GKRandomSource.sharedRandom().nextInt()
这就产生了一个介于- 2147,483,648到2147,483,647之间的数字。如果你想要一个介于0和上界(不包含)之间的数字,你可以使用这个:
GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
GameplayKit内置了一些方便的构造函数来处理骰子。例如,你可以像这样掷一个六面骰子:
let d6 = GKRandomDistribution.d6()
d6.nextInt()
此外,你还可以使用GKShuffledDistribution之类的东西来塑造随机分布。这需要更多解释,但如果你感兴趣,你可以阅读我关于GameplayKit随机数的教程。
使用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范围内,你不需要输出是在这个范围之外。
Swift 4.2编辑
从Swift 4.2开始,你可以使用Swift自己的本地函数,而不是使用导入的C函数arc4random_uniform()。
// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)
你也可以使用random(in:)来获取其他原始值的随机值;比如Int型,Double型,Float型,甚至Bool型。
Swift版本< 4.2
该方法将在给定的最小值和最大值之间生成一个随机Int值
func randomInt(min: Int, max: Int) -> Int {
return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
推荐文章
- 为什么Swift的编译时间这么慢?
- 如何测试等价的Swift枚举与相关的值
- 生成具有给定(数值)分布的随机数
- 如何创建一个Swift Date对象?
- 在Swift中转换Float为Int
- 在php中生成一个随机密码
- GLSL的随机/噪声函数
- 快速提取正则表达式匹配
- 如何应用梯度的背景视图的iOS Swift应用程序
- 我如何在Swift中声明一个弱引用数组?
- java.util.Random和java.security. securerrandom的区别
- 如何用SwiftUI调整图像大小?
- 0到1之间的随机数?
- 如何分配一个行动UIImageView对象在Swift
- 在iOS8中使用Swift更改特定视图控制器的状态栏颜色