5

让我首先说明我要完成的工作:

  1. 我需要在一个范围内随机生成一组数字
  2. 我希望这些数字有点均匀分布
  3. 我需要能够为随机数生成播种,以便在给定种子的情况下,生成的随机数将始终相同。

在对 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,因为它在第一次被调用时播种,并且不一定“设计”为在外部播种。

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

谢谢, - 亚当

4

2 回答 2

21

我知道“GameKit”听起来像是只用于游戏,但它包含一个严肃的随机数生成系统。我建议你看看GKMersenneTwisterRandomSourceGKRandomDistributionGKMersenneTwisterRandomSource接受一个随机种子(如果你选择的话)并且该类GKRandomDistribution实现了一个Uniform Distribution。一起使用,它们完全符合您的要求。

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())
}
于 2016-07-31T01:10:30.213 回答
2

事实证明, 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 范围内有点均匀分布。我不能确定是否有一种“更统一”的方式来做到这一点,但我认为有,因为我已经读过 arc4random 在统一随机数生成方面优于 drand / rand / erand / etc 函数,但是至少这似乎符合我的需要。

如果其他人想出更好的方法来完成我所追求的目标,我会将这个问题留待一段时间。

于 2016-07-31T05:25:03.027 回答