What is the equivalent of seeded random in Swift3 (Xcode8 beta 1)

你。 提交于 2019-11-30 05:54:22

问题


I need to start the same random number list over every execution of my app. srand/rand do not exist anymore. What should I do then?

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] }
    }

回答1:


You can use srand48(seed) and drand48() in Swift3.




回答2:


Unless you're developing with Swift for non-Apple platforms, you can get a much better randomization API in GameplayKit: several algorithms (trade randomness vs speed), seedable, distribution control, etc.




回答3:


I can't find a way to use seeded random in Swift 3 Beta 1. Had to write a silly wrapper function in 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();
}

You can use the bridging header to import it into Swift. Then you can call it in Swift like this:

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

random is better than rand. Read the man pages for discussion on these 2 functions.


Edit:

A workaround, as @riskter suggested, is to use 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)
}



回答4:


For a simple repeatable random list try using a Linear Congruential Generator:

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())
}

More info here: https://rosettacode.org/wiki/Linear_congruential_generator




回答5:


I just happened to put this together for Swift 4. I am aware Swift 4.2 has new random extensions that are different from this, but like the OP, I needed them to be seedable during testing. Maybe someone will find it helpful. If you don't seed it, it will use arc4random, otherwise it will use drand48. It avoids mod bias both ways.

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()


来源:https://stackoverflow.com/questions/37872765/what-is-the-equivalent-of-seeded-random-in-swift3-xcode8-beta-1

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!