Swift3 (Xcode8 beta 1) 中的随机种子是什么?
What is the equivalent of seeded random in 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[[=11=]] }
}
我找不到在 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)
}
除非您使用 Swift 为非 Apple 平台开发,否则您可以在 GameplayKit 中获得更好的随机化 API:多种算法(交易随机性与速度)、可播种、分布控制等
对于简单的可重复随机列表,请尝试使用线性同余生成器:
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
你可以使用
srand48(seed) 和 drand48() 在 Swift3.
我只是碰巧把它放在一起用于 Swift 4。我知道 Swift 4.2 有与此不同的新随机扩展,但像 OP 一样,我需要它们是可播种的在测试期间。也许有人会发现它有帮助。如果你不做种子,它会使用arc4random,否则它会使用drand48。它避免了 mod 双向偏差。
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([=10=])))
}
static let seedableGenerator = Random(){
Int(drand48() * Double([=10=]))
}
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()
我需要在每次执行我的应用程序时启动相同的随机数列表。 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[[=11=]] }
}
我找不到在 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)
}
除非您使用 Swift 为非 Apple 平台开发,否则您可以在 GameplayKit 中获得更好的随机化 API:多种算法(交易随机性与速度)、可播种、分布控制等
对于简单的可重复随机列表,请尝试使用线性同余生成器:
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
你可以使用 srand48(seed) 和 drand48() 在 Swift3.
我只是碰巧把它放在一起用于 Swift 4。我知道 Swift 4.2 有与此不同的新随机扩展,但像 OP 一样,我需要它们是可播种的在测试期间。也许有人会发现它有帮助。如果你不做种子,它会使用arc4random,否则它会使用drand48。它避免了 mod 双向偏差。
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([=10=])))
}
static let seedableGenerator = Random(){
Int(drand48() * Double([=10=]))
}
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()