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 をシードすることはできません。これは、arc4random が最初に呼び出されたときにシードされ、外部からシードされるように必ずしも「設計」されているとは限らないためです。

私の質問です。特定のシードに対して同じ出力が得られる srand() / rand() のより良い代替手段はありますが、それらの出力はより均一に分散されていますか?

ありがとう - アダム

4

2 に答える 2

21

「GameKit」はゲーム専用のように聞こえますが、本格的な乱数生成システムが含まれています。GKMersenneTwisterRandomSourceGKRandomDistributionをご覧になることをお勧めします。はGKMersenneTwisterRandomSourceランダム シード (選択した場合) を取り、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

}

上記のはるかに単純な形式で書くと、問題が明らかになります。ループの反復ごとにシードを再設定していましたが、シード値は直線的に増加していました。このため、ランダムな結果も直線的に増加していました。

簡単な解決策は、ループの反復ごとに再シードするのではなく、ループの前に 1 回シードすることです。例えば:

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 / 等の均一乱数生成関数よりも「はるかに優れている」と読んだので、あると思いますが、少なくともこれは私のニーズに合っているようです。

他の誰かが私が求めていることを達成するためのより良いアプローチを思いついた場合に備えて、私はこの質問をしばらく開いたままにします.

于 2016-07-31T05:25:03.027 に答える