RandomKit 5.2.3

RandomKit 5.2.3

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2017年8月
SwiftSwift 版本3.2
SPM支持 SPM

Nikolai Vazquezphimage 维护。



 
依赖关系
ShiftOperations~> 1.0.2
Threadly~> 1.0
 

RandomKit 5.2.3

codebeat badge

RandomKit 是一个 Swift 框架,它使得随机数据生成变得简单和容易。

构建状态

分支 状态
master

安装

兼容性

  • 平台
    • macOS 10.9+
    • iOS 8.0+
    • watchOS 2.0+
    • tvOS 9.0+
    • Linux
  • Xcode 8.0+
  • Swift 3.0.2+ & 4.0

RandomKit 可能也与 FreeBSD、Android 和 Windows(在 Cygwin 下)兼容,但尚未对这些平台进行测试。

使用 Swift 包管理器安装

Swift 包管理器 是 Swift 的去中心化依赖管理器。

  1. 将项目添加到您的 Package.swift

    import PackageDescription
    
    let package = Package(
        name: "MyAwesomeProject",
        dependencies: [
            .Package(url: "https://github.com/nvzqz/RandomKit.git",
                     majorVersion: 5)
        ]
    )
  2. 导入 RandomKit 模块。

    import RandomKit

基准测试

可以通过运行 benchmark.sh 来轻松进行 RandomKit 各个组件的基准测试。

./benchmark.sh [FLAGS] [PROTOCOLS]

使用 --help 标志获取有关如何使用它的信息。

注意:默认计数为10000000,如果在使用--array标志时,这将会非常多。这可以通过传递参数到--count-c来更改。

用法

亲自试试!下载仓库并打开'RandomKit.playground'。

RandomGenerator

RandomGenerator协议定义了生成基础值和随机化缓冲区的基本方法。

所有符合RandomGenerator的类型都提供一个静态的default值,可以作为生成函数中的inout参数传值。

let value = Int.random(using: &Xoroshiro.default)

可用的生成器

  • ARC4Random

    • 由于在Linux和其他平台上,arc4random家族函数的符号没有和Foundation一起导出,它们是动态在运行时加载的。
  • DeviceRandom

    • 从"/dev/random"或"/dev/urandom"读取作为其来源。
  • MersenneTwister

  • Xoroshiro

  • Xorshift

  • XorshiftStar

  • ChaCha

可播种随机生成器

SeedableRandomGenerator是为那些可以播种相应的Seed类型的类型设计的。

RandomBytesGenerator

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)

  • v4.4.0
  • 之前,可以通过实例化给定RandomGenerator类型的新的带种子的实例来实现线程安全。这样的问题是每次都会进行不必要的播种。使用这个,生成器只会被播种一次,之后可以在以后的点重复使用。

    还有生成器重新播种版本的快捷方式

    Xoroshiro.withThreadLocalReseeding {
        ...
    }

    这比编写要好得多

    ReseedingRandomGenerator.withThreadLocal(createdWith: { Xoroshiro.reseeding }) {
        ...
    }

    协议

    RandomKit非常注重于协议,这使得它非常灵活和模块化。

    Random

    为一个协议,用于可以生成使用RandomGenerator随机值的类型。

    RandomInRange

    为一个协议,用于可以生成使用RandomGenerator在范围内的可选随机值的类型。

    Int.random(in: 0 ..< 0, using: &randomGenerator) // nil

    RandomInClosedRange

    使用RandomGenerator生成闭区间内随机值的类型的协议。

    Int.random(in: -100 ... 100, using: &randomGenerator) // -79

    RandomToValue

    生成从基本值到另一值(非包含)的随机值的类型的协议。

    整数的基本值为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

    RandomThroughValue

    生成从基本值到另一值(包含)的随机值的类型的协议。

    RandomToValue的基本值规则也适用于RandomThroughValue

    RandomRetrievable

    类型实例可以具有可检索的随机元素的协议。

    ["Bob", "Cindy", "May", "Charles", "Javier"].random(using: &randomGenerator)  // "Charles"
    
    "Hello".characters.random(using: &randomGenerator)  // "e"

    一些Foundation类型如NSArray符合此协议。

    RandomRetrievableInRange

    类型实例可以从Range(<Index>)内部检索随机元素的协议。

    [20, 37, 42].random(in: 1 ..< 3, using: &randomGenerator)  // Either 37 or 42

    Shuffleable

    元素可以被洗牌的类型的协议。

    // 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:)就地洗牌。

    UniqueShuffleable

    类似于Shuffleable,但没有任何元素是其初始位置。

    Swift 类型

    整数

    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:),它有1weight中的概率为true

    字符串、字符和Unicode标量

    StringCharacterUnicodeScalar默认生成`" "..."~"`范围内的值。

    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

    基础类型

    日期

    可以生成介于两个 DateTimeInterval 值之间的随机 Date

    默认的 random(using:) 函数返回一个在 Date.distantPastDate.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

    NSNumber

    可以从整数或双精度浮点数范围内生成随机数,或默认为 0...100

    NSNumber.random(using: &randomGenerator)                 // 79
    NSNumber.random(in: -50...100, using: &randomGenerator)  // -27
    NSNumber.random(in: 100...200, using: &randomGenerator)  // 149.6156950363926

    Cocoa 和 UIKit 类型

    NSColor 和 UIColor

    可以生成一个随机的颜色,可以带有或没有随机的 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

    CoreGraphics 类型

    CGFloat

    因为 CGFloat 符合 FloatingPoint,所以它符合 RandomInClosedRange 协议,就像 DoubleFloat 一样。

    CGFloat.random(using: &randomGenerator)               // 0.699803650379181
    CGFloat.random(in: 0...100, using: &randomGenerator)  // 43.27969591675319

    CGPoint

    可以从 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

    可以从宽度、高度的范围内生成一个随机大小。

    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}

    CGRect

    可以从 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}

    CGVector

    可以从 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}

    附加内容

    BigInt

    RandomKitBigInt 中提供了 RandomKit 对 Károly 的 BigInt 库的扩展。

    许可证

    RandomKit 及其资产在 MIT 许可证 下发布。资产可以在 assets 分支中找到。

    本项目部分使用由Matt Gallagher编写的代码,并与MIT许可证结合,在此取得了相同的许可。