测试已测试 | ✓ |
语言语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2017年8月 |
SwiftSwift 版本 | 3.2 |
SPM支持 SPM | ✓ |
由 Nikolai Vazquez,phimage 维护。
依赖关系 | |
ShiftOperations | ~> 1.0.2 |
Threadly | ~> 1.0 |
RandomKit 是一个 Swift 框架,它使得随机数据生成变得简单和容易。
分支 | 状态 |
---|---|
master |
RandomKit 可能也与 FreeBSD、Android 和 Windows(在 Cygwin 下)兼容,但尚未对这些平台进行测试。
Swift 包管理器 是 Swift 的去中心化依赖管理器。
将项目添加到您的 Package.swift
。
import PackageDescription
let package = Package(
name: "MyAwesomeProject",
dependencies: [
.Package(url: "https://github.com/nvzqz/RandomKit.git",
majorVersion: 5)
]
)
导入 RandomKit 模块。
import RandomKit
可以通过运行 benchmark.sh
来轻松进行 RandomKit 各个组件的基准测试。
./benchmark.sh [FLAGS] [PROTOCOLS]
使用 --help
标志获取有关如何使用它的信息。
注意:默认计数为10000000,如果在使用--array
标志时,这将会非常多。这可以通过传递参数到--count
或-c
来更改。
亲自试试!下载仓库并打开'RandomKit.playground'。
RandomGenerator
协议定义了生成基础值和随机化缓冲区的基本方法。
所有符合RandomGenerator
的类型都提供一个静态的default
值,可以作为生成函数中的inout
参数传值。
let value = Int.random(using: &Xoroshiro.default)
ARC4Random
arc4random
家族函数的符号没有和Foundation一起导出,它们是动态在运行时加载的。DeviceRandom
MersenneTwister
Xoroshiro
Xorshift
XorshiftStar
ChaCha
SeedableRandomGenerator
是为那些可以播种相应的Seed
类型的类型设计的。
RandomBytesGenerator
协议是为那些专门生成填充了一定数量字节的特定类型类型设计的。例如,MersenneTwister
专门生成UInt64
,而Xorshift
生成UInt32
值。
对于单线程程序,可以使用全局生成实例,如Xoroshiro.default
作为随机数源,这是安全的。
对于多线程程序,应使用线程局部实例。这允许不同的线程使用它们自己的独立随机生成器,而不需要共享可变状态。
在下面的示例中,randomGenerator
对每个线程都是唯一的。
let randomBytes = Xoroshiro.withThreadLocal { randomGenerator in
return [UInt8](randomCount: 1000, using: &randomGenerator)
}
线程局部生成器在线程退出时被释放,因此不必担心清理。
建议不要每次都调用withThreadLocal(_:)
或获取threadLocal
指针。检索线程局部实例导致不必要的开销。
// Bad
let value = Int.random(using: &Xoroshiro.threadLocal.pointee)
array.shuffle(using: &Xoroshiro.threadLocal.pointee)
// Good
let threadLocal = Xoroshiro.threadLocal
let value = Int.random(using: &threadLocal.pointee)
array.shuffle(using: &threadLocal.pointee)
// Better
Xoroshiro.withThreadLocal { randomGenerator in
let value = Int.random(using: &randomGenerator)
array.shuffle(using: &randomGenerator)
}
作为一个快捷方式,甚至可以直接将一个函数作为参数应用。
let value = Xoroshiro.withThreadLocal(Int.random)
在RandomGenerator
类型的新的带种子的实例来实现线程安全。这样的问题是每次都会进行不必要的播种。使用这个,生成器只会被播种一次,之后可以在以后的点重复使用。
还有生成器重新播种版本的快捷方式
Xoroshiro.withThreadLocalReseeding {
...
}
这比编写要好得多
ReseedingRandomGenerator.withThreadLocal(createdWith: { Xoroshiro.reseeding }) {
...
}
RandomKit非常注重于协议,这使得它非常灵活和模块化。
为一个协议,用于可以生成使用RandomGenerator
随机值的类型。
为一个协议,用于可以生成使用RandomGenerator
在范围内的可选随机值的类型。
Int.random(in: 0 ..< 0, using: &randomGenerator) // nil
使用RandomGenerator
生成闭区间内随机值的类型的协议。
Int.random(in: -100 ... 100, using: &randomGenerator) // -79
生成从基本值到另一值(非包含)的随机值的类型的协议。
整数的基本值为0。这意味着对负值调用random(to:using:)
将产生随机负数或零,而对正值调用将产生随机正数或零。
如果value
等于randomBase
,则对于random(to:using:)
会返回value
。
Int.random(to: 2, using: &randomGenerator) // Either 0 or 1
Int.random(to: 0, using: &randomGenerator) // Always 0
Int.random(to: 32, using: &randomGenerator) // 15
Int.random(to: -5, using: &randomGenerator) // -3
生成从基本值到另一值(包含)的随机值的类型的协议。
RandomToValue
的基本值规则也适用于RandomThroughValue
。
类型实例可以具有可检索的随机元素的协议。
["Bob", "Cindy", "May", "Charles", "Javier"].random(using: &randomGenerator) // "Charles"
"Hello".characters.random(using: &randomGenerator) // "e"
一些Foundation类型如NSArray
符合此协议。
类型实例可以从Range(<Index>)
内部检索随机元素的协议。
[20, 37, 42].random(in: 1 ..< 3, using: &randomGenerator) // Either 37 or 42
元素可以被洗牌的类型的协议。
// Array
[1, 2, 3, 4, 5].shuffled(using: &randomGenerator) // [3, 4, 1, 5, 2]
// Dictionary
["a": 1, "b": 2, "c": 3].shuffled(using: &randomGenerator) // ["a": 3, "b": 1, "c": 2]
shuffled(using:)
的可变版本是shuffle(using:)
。
为了更好的Array
洗牌性能,考虑使用shuffle(using:)
就地洗牌。
类似于Shuffleable
,但没有任何元素是其初始位置。
Swift的所有原生整数类型都符合Random-
协议。
random(using:)
函数创建任何值的整数。因此,对于有符号整数,可能会导致负值。
Int.random(using: &randomGenerator) // An Int within Int.min and Int.max
Int.random(in: 10...20, using: &randomGenerator) // An Int within 10 and 20
要创建正的有符号整数,请使用random(to:using:)
或random(through:using:)
。
Int.random(to: 1000, using: &randomGenerator) // 731
Int.random(through: 10, using: &randomGenerator) // 4
有符号整数可以从任何范围创建,没有溢出的风险。
Int.random(in: (.min + 1000)...(.max - 200), using: &randomGenerator) // 5698527899712144154
通过一个范围或默认情况下从`0.0...1.0`生成随机浮点值。
Double.random(using: &randomGenerator) // 0.9813615573117475
Double.random(in: -10...10, using: &randomGenerator) // -4.03042337718197
Float.random(in: -10...10, using: &randomGenerator) // 5.167088
Float80.random(in: -10...10, using: &randomGenerator) // -3.63204542399198874
所有`FloatingPoint`类型也可以默认符合`RandomInClosedRange`。
Bool.random(using:)
有50/50的概率为true
。
如果需要不同的概率,还可以使用random(withWeight:using:)
,它有1
在weight
中的概率为true
。
String
、Character
和UnicodeScalar
默认生成`" "..."~"`范围内的值。
String.random(ofLength: 10, using: &randomGenerator) // "}+[=Ng>$w1"
String.random(ofLength: 10, in: "A"..."z", using: &randomGenerator) // "poUtXJIbv["
Character.random(using: &randomGenerator) // "#"
Character.random(in: "A"..."z", using: &randomGenerator) // "s"
可以使用 init(randomCount:using:)
为符合 Random
协议的类型生成随机值数组。
所有其他 Random-
协议也存在类似的初始化器。
let randoms = Array<Int>(randomCount: 100, using: &randomGenerator) // [8845477344689834233, -957454203475087100, ...]
对于符合 UnsafeRandom
协议的类型,有一个更快的替代方法是 init(unsafeRandomCount:using:)
。这个初始化器直接填充缓冲区,而不是使用 random(using:)
。
let unsafeRandoms = Array<Int>(unsafeRandomCount: 100, using: &randomGenerator) // [759709806207883991, 4618491969012429761, ...]
生成 1000 个包含 10000 个元素随机的 Int
数组的性能测试
生成器 | 时间(以秒为单位) |
---|---|
Xoroshiro |
0.0271 |
Xorshift |
0.0568 |
XorshiftStar |
0.0319 |
ChaCha |
0.2027 |
MersenneTwister |
0.0432 |
ARC4Random |
0.2416 |
DeviceRandom |
5.3348 |
注意:由于各种因素的影响,结果可能会有所不同。
可以使用以下方式运行相同的基准测试:
./benchmark.sh --all-generators --array 10000 --count 1000
可以生成介于两个 Date
或 TimeInterval
值之间的随机 Date
。
默认的 random(using:)
函数返回一个在 Date.distantPast
和 Date.distantFuture
之间的 Date
。
Date.random(using: &randomGenerator) // "Aug 28, 2006, 3:38 AM"
Date.random(in: Date.distantPast...Date(), using: &randomGenerator) // "Feb 7, 472, 5:40 AM"
Decimal
类型符合多个 Random-
协议。
默认情况下,random(using:)
函数返回介于 0 和 1 之间的 Decimal
值。
Decimal.random(using: &randomGenerator) // 0.87490000409886706715888973957833129437
Decimal.random(in: 0.0...10.0, using: &randomGenerator) // 6.5464639772070720738747790627821299859
可以从整数或双精度浮点数范围内生成随机数,或默认为 0...100
。
NSNumber.random(using: &randomGenerator) // 79
NSNumber.random(in: -50...100, using: &randomGenerator) // -27
NSNumber.random(in: 100...200, using: &randomGenerator) // 149.6156950363926
可以生成一个随机的颜色,可以带有或没有随机的 alpha 值。
NSColor.random(using: &randomGenerator) // r 0.694 g 0.506 b 0.309 a 1.0
NSColor.random(alpha: true, using: &randomGenerator) // r 0.859 g 0.57 b 0.409 a 0.047
UIColor.random(using: &randomGenerator) // r 0.488 g 0.805 b 0.679 a 1.0
UIColor.random(alpha: true, using: &randomGenerator) // r 0.444 g 0.121 b 0.602 a 0.085
因为 CGFloat
符合 FloatingPoint
,所以它符合 RandomInClosedRange
协议,就像 Double
和 Float
一样。
CGFloat.random(using: &randomGenerator) // 0.699803650379181
CGFloat.random(in: 0...100, using: &randomGenerator) // 43.27969591675319
可以从 x 和 y 的范围内生成一个随机点。
CGPoint.random(using: &randomGenerator) // {x 70.093 y 95.721}
CGPoint.random(xRange: 0...200, yRange: 0...10, using: &randomGenerator) // {x 73.795 y 0.991}
可以从宽度、高度的范围内生成一个随机大小。
CGSize.random(using: &randomGenerator) // {w 3.744 h 35.932}
CGSize.random(widthRange: 0...50, heightRange: 0...400, using: &randomGenerator) // {w 38.271 h 239.636}
可以从 x、y、宽度、高度的范围内生成一个随机矩形。
CGRect.random(using: &randomGenerator) // {x 3.872 y 46.15 w 8.852 h 20.201}
CGRect.random(xRange: 0...50,
yRange: 0...100,
widthRange: 0...25,
heightRange: 0...10,
using: &randomGenerator) // {x 13.212 y 79.147 w 20.656 h 5.663}
可以从 dx 和 dy 的范围内生成一个随机向量。
CGVector.random(using: &randomGenerator) // {dx 13.992 dy 89.376}
CGVector.random(dxRange: 0...50, dyRange: 0...10, using: &randomGenerator) // {dx 35.224 dy 13.463}
在 RandomKitBigInt 中提供了 RandomKit 对 Károly 的 BigInt 库的扩展。
RandomKit 及其资产在 MIT 许可证 下发布。资产可以在 assets
分支中找到。
本项目部分使用由Matt Gallagher编写的代码,并与MIT许可证结合,在此处取得了相同的许可。