Swift 4.2+播种随机数生成器

问题描述 投票:0回答:1

我正在尝试使用带有Int.random()函数的Swift 4.2+生成种子随机数,但是没有给定的实现允许随机数生成器被播种。据我所知,唯一的方法是创建一个符合RandomNumberGenerator协议的新随机数生成器。有没有人建议更好的方法,或者具有种子功能的RandomNumberGenerator符合类的实现,以及如何实现它?

此外,我已经看到两个函数sranddrand提到了几次,而我正在寻找解决方案,但从它提到的很少,我不确定使用它是不好的约定,我也可以'找到关于它们的任何文档。

我正在寻找最简单的解决方案,不一定是最安全或最快的解决方案(例如使用外部库不是理想的)。

更新:通过“种子”,我的意思是我要将种子传递给随机数生成器,这样如果我将相同的种子传递给两个不同的设备或两次不同的时间,生成器将产生相同的数字。目的是我为应用程序随机生成数据,而不是将所有数据保存到数据库,我希望每次用户加载应用程序时保存种子并使用该种子重新生成数据。

swift random swift4.2 random-seed
1个回答
1
投票

所以我使用Martin R的建议来使用GamePlayKitGKMersenneTwisterRandomSource来创建一个符合RandomNumberGenerator协议的类,我可以使用像Int.random()这样的函数的实例:

import GameplayKit

class SeededGenerator: RandomNumberGenerator {
    let seed: UInt64
    private let generator: GKMersenneTwisterRandomSource
    convenience init() {
        self.init(seed: 0)
    }
    init(seed: UInt64) {
        self.seed = seed
        generator = GKMersenneTwisterRandomSource(seed: seed)
    }
    func next<T>(upperBound: T) -> T where T : FixedWidthInteger, T : UnsignedInteger {
        return T(abs(generator.nextInt(upperBound: Int(upperBound))))
    }
    func next<T>() -> T where T : FixedWidthInteger, T : UnsignedInteger {
        return T(abs(generator.nextInt()))
    }
}

用法:

// Make a random seed and store in a database
let seed = UInt64.random(in: UInt64.min ... UInt64.max)
var generator = Generator(seed: seed)
// Or if you just need the seeding ability for testing,
// var generator = Generator()
// uses a default seed of 0

let chars = ['a','b','c','d','e','f']
let randomChar = chars.randomElement(using: &generator)
let randomInt = Int.random(in: 0 ..< 1000, using: &generator)
// etc.

通过结合GKMersenneTwisterRandomSource的种子功能和标准库的随机函数的简单性(如.randomElement()用于数组,.random()用于Int,Bool,Double等),这给了我灵活性和易于实现的功能。


0
投票

这里是RPatel99答案的替代方案,它考虑了GKRandom值的范围。

import GameKit

struct ArbitraryRandomNumberGenerator : RandomNumberGenerator {

    mutating func next() -> UInt64 {
        // GKRandom produces values in [INT32_MIN, INT32_MAX] range; hence we need two numbers to produce 64-bit value.
        let next1 = UInt64(bitPattern: Int64(gkrandom.nextInt()))
        let next2 = UInt64(bitPattern: Int64(gkrandom.nextInt()))
        return next1 | (next2 << 32)
    }

    init(seed: UInt64) {
        self.gkrandom = GKMersenneTwisterRandomSource(seed: seed)
    }

    private let gkrandom: GKRandom
}
© www.soinside.com 2019 - 2024. All rights reserved.