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
}
}
}
public extension ExpressibleByIntegerLiteral {
public static func arc4random() -> Self {
var r: Self = 0
arc4random_buf(&r, MemoryLayout<Self>.size)
return r
}
}
现在我们可以做到:
let i = Int.arc4random()
let j = UInt32.arc4random()
和所有其他整数类都可以 .
5
10(0-9)之间随机数的例子;
import UIKit
let randomNumber = Int(arc4random_uniform(10))
非常简单的代码 - 简单而简短 .
0
你可以像在C中那样做:
let randomNumber = arc4random()
推断 randomNumber 的类型为 UInt32 (32位无符号整数)
4
详情
xCode 9.1,Swift 4
面向数学的解决方案(1)
import Foundation
class Random {
subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
get {
return rand(min-1, max+1)
}
}
}
let rand = Random()
func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
let _min = min + 1
let difference = max - _min
return T(arc4random_uniform(UInt32(difference))) + _min
}
解决方案的使用(1)
let x = rand(-5, 5) // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10] // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
面向程序员的解决方案(2)
别忘了添加数学面向解决方案(1)代码在这里
import Foundation
extension CountableRange where Bound : BinaryInteger {
var random: Bound {
return rand(lowerBound-1, upperBound)
}
}
extension CountableClosedRange where Bound : BinaryInteger {
var random: Bound {
return rand[lowerBound, upperBound]
}
}
解决方案的使用(2)
let x = (-8..<2).random // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]
25 回答
我已经能够使用
rand()
来获得一个随机的CInt . 您可以使用以下内容将其设为Int:您可以使用自己喜欢的C随机函数,如果需要,只需将值转换为Int即可 .
我用过这段代码:
Edit for Swift 4.2
从Swift 4.2开始,您现在可以使用Swift自己的本机函数,而不是使用导入的C函数arc4random_uniform() .
您也可以使用
random(in:)
获取其他原始值的随机值;比如Int,Double,Float甚至Bool .Swift versions < 4.2
此方法将在给定的最小值和最大值之间生成随机
Int
值您可以像这样使用
GeneratorOf
:Swift 4.2
Swift 4.2在标准库中包含了一个原生且功能齐全的随机数API . (Swift Evolution proposal SE-0202)
所有数字类型都具有静态random(in:),它取范围并返回给定范围内的随机数
这里5将确保随机数生成为零到五 . 您可以相应地设置值 .
使用标准库函数获得高质量的随机数:
arc4random()
或arc4random_uniform()
,就像在Objective-C中一样 .它们位于
Darwin
模块中,因此如果您尚未导入AppKit
,UIKit
或Foundation
(为您导入它),则需要import Darwin
.Swift 4.2
随Xcode 10一起提供的Swift 4.2为许多数据类型引入了易于使用的新随机函数 . 您可以在数字类型上调用
random()
方法 .对于iOS,macOS和tvOS,您可以在Xcode的框架
GameKit
中使用 system-wide random source . 在这里你可以找到GKRandomSource
类及其sharedRandom()
类方法:或者只使用
randomElement()
方法返回集合的随机元素:Edit: Updated for Swift 3.0
arc4random
在Swift中运行良好,但基本功能仅限于32位整数类型(Int
在iPhone 5S和现代Mac上为64位) . 这是一个由整数文字表示的随机数类型的通用函数:我们可以使用这个新的泛型函数来扩展
UInt64
,添加边界参数和减轻模偏差 . (这是从arc4random.c直接解除的)有了这个,我们可以为相同的参数扩展
Int64
,处理溢出:完成家庭......
毕竟,我们终于可以这样做了:
我使用此代码生成一个随机数:
自Swift 4.2以来
有一组新的API:
所有 numeric 类型现在都有random(in:)方法,需要
range
.它返回在该范围内均匀分布的数字 .
TL;DR
那么,“好”旧方式有什么问题?
您必须使用导入的C API(它们在平台之间是不同的) .
此外......
如果使用
arc4random()
(计算余数),如arc4random() % aNumber
,结果 is not 均匀分布在0
和aNumber
之间 . 有一个叫 Modulo bias 的问题 .Modulo bias
通常,该函数会在
0
和MAX之间生成一个随机数(取决于类型等) . 为了做一个快速简单的例子,假设最大数字是7
并且您关心0 ..< 2
范围内的随机数(或者如果您愿意,则关注区间[0,3]) .个人号码的 probabilities 是:
0:3/8 = 37.5%
1:3/8 = 37.5%
2:2/8 = 25%
换句话说,你最终会以0或1结束 . 当然,请记住,这是非常简化的,并且MAX数字要高得多,这使得它更多"fair" .
@jstn's answer很好,但有点冗长 . Swift被称为面向协议的语言,因此我们可以通过添加协议扩展的默认实现来实现相同的结果,而无需为整数族中的每个类实现样板代码 .
现在我们可以做到:
和所有其他整数类都可以 .
10(0-9)之间随机数的例子;
非常简单的代码 - 简单而简短 .
你可以像在C中那样做:
推断
randomNumber
的类型为UInt32
(32位无符号整数)详情
xCode 9.1,Swift 4
面向数学的解决方案(1)
解决方案的使用(1)
面向程序员的解决方案(2)
解决方案的使用(2)
完整样本
样本结果
从iOS 9开始,您可以使用新的GameplayKit类以多种方式生成随机数 .
您有四种源类型可供选择:一般随机源(未命名,下至系统选择它的作用),线性同余,ARC4和Mersenne Twister . 这些可以产生随机的整数,浮点数和布尔值 .
在最简单的级别,您可以从系统的内置随机源生成一个随机数,如下所示:
这产生了-2,147,483,648和2,147,483,647之间的数字 . 如果你想要一个介于0和上限(独占)之间的数字,你可以使用:
GameplayKit内置了一些方便的构造函数来处理骰子 . 例如,您可以像这样滚动六面模具:
另外,您可以使用GKShuffledDistribution之类的内容来塑造随机分布 . 这需要更多的解释,但如果你感兴趣,你可以read my tutorial on GameplayKit random numbers .
以下代码将生成0到255之间的安全随机数:
你这样称呼它:
对于更大的数字,它变得更复杂 .
这是我能想到的最好的:
这些方法使用额外的随机数来确定将使用多少
UInt8
来创建随机数 . 最后一行将[UInt8]
转换为UInt16
或UInt32
.我不知道最后两个仍然算是真正的随机,但你可以调整它你的喜好:)
Swift 4.2
再见,导入Foundation C lib
arc4random_uniform()
您使用random(in :)从范围生成随机数字 .
randomElement()如果范围为空则返回nil,所以你打开返回的Int?如果让 .
您使用random(in :)生成随机Double,Float或CGFloat和random()以返回随机Bool .
More @ Official
这是一个很好地完成工作的图书馆https://github.com/thellimist/SwiftRandom
使用
arc4random_uniform(n)
表示0到n-1之间的随机整数 .将结果转换为Int,这样您就不必将变量显式键入
UInt32
(这似乎是非Swifty) .在某些版本的Xcode中没有arc4Random_uniform()(在7.1中它运行但不为我自动完成) . 你可以这样做 .
从0-5生成随机数 . 第一
然后
我想补充一下现有的答案,即Swift书中的随机数生成器示例是一个线性同余生成器(LCG),它是一个非常有限的,并且根本不应该是重要的 . 和 a LCG should never be used for cryptographic purposes .
arc4random()
好多了,可以用于大多数用途,但是 should not be used for cryptographic purposes.如果您想要保证加密安全的内容,请使用
SecCopyRandomBytes()
. 请注意,如果您将随机数生成器构建为某些内容,则其他人可能最终(误)将其用于加密目的(例如密码,密钥或盐生成),那么即使您需要,也应该考虑使用SecCopyRandomBytes()
不太需要 .使用arc4random_uniform()
Usage:
arc4random_uniform(someNumber: UInt32) -> UInt32
这将为您提供
0
至someNumber - 1
范围内的随机整数 .UInt32
的最大值为4,294,967,295(即2^32 - 1
) .Examples:
General form:
其中
number
,max
和min
是UInt32
.怎么样......
arc4random()
您还可以使用
arc4random()
获取一个随机数,它产生一个介于0和2 ^ 32-1之间的UInt32
. 因此,要获得0
和x-1
之间的随机数,您可以将其除以x
并取余数 . 或者换句话说,使用Remainder Operator (%):但是,这会产生轻微的modulo bias(另请参见here和here),因此建议使用
arc4random_uniform()
.Converting to and from Int
通常,做这样的事情以便在
Int
和_514637之间来回转换会很好:但问题是Int在32位系统上的范围为
-2,147,483,648...2,147,483,647
,在64位系统上的范围为-9,223,372,036,854,775,808...9,223,372,036,854,775,807
. 将其与0...4,294,967,295
的UInt32
范围进行比较 .UInt32
的U
表示未签名 .请考虑以下错误:
因此,您只需确保输入参数在
UInt32
范围内,并且您不需要输出超出该范围 .在 Swift 4.2 中,您可以通过在所需的任何数字类型上调用
random()
方法来生成随机数,从而提供您要使用的范围 . 例如,这会生成1到9范围内的随机数,包括两侧还有其他类型