Swift 4.2+ заполняет генератор случайных чисел - PullRequest
0 голосов
/ 22 февраля 2019

Я пытаюсь сгенерировать случайные числа с засечками с помощью Swift 4.2+, с помощью функции Int.random(), однако не существует конкретной реализации, которая позволяла бы заполнять генератор случайных чисел.Насколько я могу судить, единственный способ сделать это - создать новый генератор случайных чисел, соответствующий протоколу RandomNumberGenerator.У кого-нибудь есть рекомендации по лучшему способу сделать это, или реализации соответствующего класса RandomNumberGenerator, который имеет функциональность «засева», и как его реализовать?

Кроме того, я видел две функции srand и drand упоминалось пару раз, когда я искал решение для этого, но, судя по тому, как редко оно упоминалось, я не уверен, что его использование является плохим соглашением, и я также не могу найти какую-либо документацию поих.

Я ищу самое простое решение, не обязательно самое безопасное или самое быстрое (например, использование внешней библиотеки не было бы идеальным).

Обновление: Под словом «отобранный» я имею в виду, что я должен был передать начальное число в генератор случайных чисел, чтобы, если я передам одно и то же начальное число двум разным устройствам или в два разных времени, генератор будет производить одинаковые числа.Цель состоит в том, чтобы я генерировал данные для приложения случайным образом, и вместо того, чтобы сохранять все эти данные в базе данных, я хочу сохранять начальное значение и регенерировать данные с этим начальным числом каждый раз, когда пользователь загружает приложение.

Ответы [ 2 ]

0 голосов
/ 06 августа 2019

Вот альтернатива ответу от 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
}
0 голосов
/ 24 февраля 2019

Итак, я использовал предложение Мартина Р. использовать GamePlayKit GKMersenneTwisterRandomSource для создания класса, соответствующего протоколу 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 и т. д.)

...