Swift - 播种arc4random_uniform?还是另类?

时间:2016-07-31 00:16:42

标签: swift random uniform-distribution

首先让我说明我想要完成的事情:

  1. 我需要在一个范围内随机生成一组数字
  2. 我希望这些数字在某种程度上均匀分布
  3. 我需要能够为随机数生成种子,这样,给定种子,结果随机数将始终相同。
  4. 在使用drand48(),rand()和arc4random()进行了相当多的实验之后,我目前已经决定使用rand()获取随机数,并使用srand()进行种子设定。这是一个从我正在做的事情简化的小例子:

    let seed: UInt32 = 10
    srand(seed)
    let start = 0
    let end = 100
    let randomNumber = Double(rand()) % (end + 1 - start) + start
    

    这很有效。给定相同的种子,出现相同的随机数。执行多个randomNumber计算会产生多个不同的随机数。通过srand重新播种开始"随机性"再次。

    唯一的缺点是rand()不是均匀分布的。事实上,我总是最终会得到一组在大多数情况下呈线性增长的数字。

    听起来arc4random_uniform会产生更多的均匀随机输出,但是根据我的研究,它不可能为arc4random播种,因为它在第一次被调用时种子化并且不一定&# 34;设计"在外部播种。

    所以我的问题;是否有更好的srand()/ rand()替代方案,它仍然会为给定的种子提供相同的输出,但这些输出更均匀地分布?

    谢谢, - 亚当

2 个答案:

答案 0 :(得分:15)

我知道" GameKit"听起来它只适用于游戏,但它包含一个严重的随机数生成系统。我建议你看看GKMersenneTwisterRandomSourceGKRandomDistributionGKMersenneTwisterRandomSource采用随机种子(如果您愿意),GKRandomDistribution类实现统一分布。一起使用,它们完全符合您的要求。

import GameKit

// The Mersenne Twister is a very good algorithm for generating random
// numbers, plus you can give it a seed...    
let rs = GKMersenneTwisterRandomSource()
rs.seed = 1780680306855649768

// Use the random source and a lowest and highest value to create a 
// GKRandomDistribution object that will provide the random numbers.   
let rd = GKRandomDistribution(randomSource: rs, lowestValue: 0, highestValue: 100)

// Now generate 10 numbers in the range 0...100:    
for _ in 1...10 {
    print(rd.nextInt())
}

print("---")

// Let's set the seed back to the starting value, and print the same 10
// random numbers.    
rs.seed = 1780680306855649768
for _ in 1...10 {
    print(rd.nextInt())
}

答案 1 :(得分:3)

事实证明,srand / rand组合适合我的需要,导致结果不出现的问题"均匀分布"我自己的逻辑是一个错误。

作为参考,基本上我正在做的是这个(实际上它要复杂得多,但出于演示目的):

let start = 0
let end = 100

for x in 0..<10 {

   let seed = UInt32(x)
   srand(seed)
   let randomNumber = Double(rand()) % (end + 1 - start) + start

   // Do something with random number

}

以上面更简单的形式编写,问题变得明显。我在循环的每次迭代中重新播种,种子值只是线性递增。因此,随机结果也呈线性递增。

简单的解决方案是不对每个循环迭代重新播种,而是在循环之前播种一次。例如:

let start = 0
let end = 100
let seed = UInt32(100)
srand(seed)

for x in 0..<10 {

   let randomNumber = Double(rand()) % (end + 1 - start) + start

   // Do something with random number

}

通过这个简单的更改,结果值似乎在示例中使用的0到100范围内有些均匀分布。我无法确定是否有更均匀的&#34;这样做的方式,但我认为,因为我已经读过arc4random是&#34;远远优于&#34; drand / rand / erand / etc函数用于统一随机数生成,但至少这似乎可以满足我的需求。

如果其他人提出更好的方法来完成我所追求的目标,我会暂时搁置这个问题。

相关问题