什么是Swift3中的种子随机数(Xcode8 beta 1)

时间:2016-06-17 03:42:17

标签: random srand swift3

我需要在每次执行应用程序时启动相同的随机数列表。 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] }
    }

5 个答案:

答案 0 :(得分:8)

你可以使用 Swift3中的 srand48(种子) drand48()

答案 1 :(得分:5)

除非您使用Swift为非Apple平台开发,否则您可以在GameplayKit中获得更好的随机化API:几种算法(交易随机性与速度),可播种,分发控制等。

答案 2 :(得分:2)

我找不到在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)
}

答案 3 :(得分:0)

对于简单的可重复随机列表,请尝试使用线性同余生成器:

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

答案 4 :(得分:0)

我刚巧把它集成到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()