Что эквивалентно сеяной случайности в Swift3 (Xcode8 beta 1)

Мне нужно запустить один и тот же список случайных чисел при каждом выполнении моего приложения. srand / rand больше не существует. Что мне тогда делать?

private extension Array {
    private func randomValues(_ seed: UInt32, num: Int) -> [Element] {
        srand (seed)

        var indices = [Int]()
        indices.reserveCapacity(num)
        let range = 0..<self.count
        for _ in 0..<num {
            var random = 0
            repeat {
                random = randomNumberInRange(range)
            } while indices.contains(random)
            indices.append(random)
        }

        return indices.map { self[$0] }
    }
 pjs17 июн. 2016 г., 16:42
Это сообщение в блоге Мэтта Галлахера может быть интересным для вас.
 Code Different17 июн. 2016 г., 06:01
Похоже, вы должны переместить свой код в C / Obj-C. Apple либо не переносит ее вовремя на Beta 1, либо слишком жестко заставляет вас использовать «хорошие» генераторы случайных чисел
 Code Different17 июн. 2016 г., 06:00
arc4random() не может быть посеян. Вы получаете случайные числа лучшего качества, но если ваше требование каждый раз запрашивает один и тот же набор случайных чисел, это не подходит.
 LC 웃17 июн. 2016 г., 05:48
используйте arc4random () вместо srand (seed)
 Code Different17 июн. 2016 г., 06:15
Менее предсказуемо, более длинный цикл, прежде чем генератор повторяется. Смотрите мой ответ для глупой обертки C
 Stéphane de Luca17 июн. 2016 г., 06:05
Да, но что вы подразумеваете под хорошим? Более высокое качество генерации? Но в любом случае, посев иногда необходим. Я бы упал с дерева, если бы яблоко не давало отобранное поколение.

Ответы на вопрос(5)

Я не могу найти способ использовать отобранные случайные числа в Swift 3 Beta 1. Пришлось написать глупую функцию-обертку в C:

// ----------------------------------------------
// my_random.h
// ----------------------------------------------
#ifndef my_random_h
#define my_random_h

#include <stdio.h>

#endif /* my_random_h */

long next_random();


// ----------------------------------------------
// my_random.c
// ----------------------------------------------
#include <stdlib.h>
#include "my_random.h"

long next_random() {
    return random();
}

Вы можете использовать соединительный заголовок, чтобы импортировать его в Swift. Тогда вы можете назвать это в Swift так:

srandom(42)
for _ in 0..<10 {
    let x = next_random()
    print(x)
}

random лучше, чемrand, Прочитайтеman страницы для обсуждения этих двух функций.

Редактировать:

Обходной путь, как предложил @riskter, заключается в использовании GameKit:

import GameKit

let seed = Data(bytes: [42]) // Use any array of [UInt8]
let source = GKARC4RandomSource(seed: seed)

for _ in 0..<10 {
    let x = source.nextInt()
    print(x)
}
 Stéphane de Luca19 июн. 2016 г., 04:53
Увы, мостовое соединение в каркасе недопустимо: «<unknown>: 0: ошибка: использование мостовых заголовков с целевыми объектами каркаса не поддерживается». Любое решение?
 Code Different20 июн. 2016 г., 03:40
Используйте GameKit согласно предложению @rickster. Смотрите мой отредактированный ответ

Мне просто довелось собрать это для Swift 4. Я знаю, что в Swift 4.2 есть новые случайные расширения, которые отличаются от этого, но, как и OP, мне нужно было, чтобы они были посеянными во время тестирования. Может быть, кто-то найдет это полезным. Если вы не заполняете его, он будет использовать arc4random, в противном случае он будет использовать drand48. Это позволяет избежать смещения модов в обоих направлениях.

import Foundation 

class Random {

    static var number = unseededGenerator // the current generator

    /**
     * returns a random Int 0..<n
     **/
    func get(anIntLessThan n: Int) -> Int {
        return generatingFunction(n)
    }

    class func set(seed: Int) {
        number = seedableGenerator
        srand48(seed)
    }

    // Don't normally need to call the rest

    typealias GeneratingFunction = (Int) -> Int

    static let unseededGenerator = Random(){
        Int(arc4random_uniform(UInt32($0)))
    }
    static let seedableGenerator = Random(){
        Int(drand48() * Double($0))
    }

    init(_ gf: @escaping GeneratingFunction) {
        self.generatingFunction = gf
    }

    private let generatingFunction: GeneratingFunction
}

func randomTest() {
    Random.set(seed: 65) // comment this line out for unseeded
    for _ in 0..<10 {
        print(
            Random.number.get(anIntLessThan: 2),
            terminator: " "
        )
    }
}


// Run

randomTest()
Решение Вопроса

Ты можешь использоватьsrand48 (семена) а такжеdrand48 () в Swift3.

Для простого повторяемого случайного списка попробуйте использовать линейный конгруэнтный генератор:

import Foundation

class LinearCongruntialGenerator
{

    var state = 0 //seed of 0 by default
    let a, c, m, shift: Int

    //we will use microsoft random by default
    init() {
        self.a = 214013
        self.c = 2531011
        self.m = Int(pow(2.0, 31.0)) //2^31 or 2147483648
        self.shift = 16
    }

    init(a: Int, c: Int, m: Int, shift: Int) {
        self.a = a
        self.c = c
        self.m = m //2^31 or 2147483648
        self.shift = shift
    }

    func seed(seed: Int) -> Void {
        state = seed;
    }

    func random() -> Int {
        state = (a * state + c) % m
        return state >> shift
    }
}

let microsoftLinearCongruntialGenerator = LinearCongruntialGenerator()

print("Microsft Rand:")

for i in 0...10
{
    print(microsoftLinearCongruntialGenerator.random())
}

Больше информации здесь:https://rosettacode.org/wiki/Linear_congruential_generator

 cyanide14 дек. 2016 г., 09:33
Мне это нравится! Только вместо Int (pow (2.0, 31.0)), который является медленным и неточным, поскольку работает с двойными значениями, я предпочитаю 1 << 31.

Если вы не разрабатываете Swift для платформ, отличных от Apple, вы можете получить гораздо лучший API рандомизации в GameplayKit: несколько алгоритмов (случайность торговли против скорости), возможность посева, управление распределением и т. Д.

 Stéphane de Luca19 июн. 2016 г., 05:15
Как бы это перевести как замену стенда / ранда?

Ваш ответ на вопрос