lua乱数の問題
1748 ワード
今日はluaのmathを見ています.random関数の場合、ランダムシードを再設定していない場合、randomが返す最初のランダム数はそれほどランダムではありません.特にランダム範囲が小さい場合、例えば100程度の場合は基本的に1を返します.ソースコードを見て内部呼び出しは(lua 5.1ソースコード):
lua_Number r = (lua_Number)(rand()%RAND_MAX)/(lua_Number)RAND_MAX;
これは実は0~1の間の小数を生成し、mathに基づいている.randomのパラメータの個数で操作します.
パラメータがない場合はこの数を直接返します.もちろん、切断されます.
パラメータが1つある場合、floor(r*u)+1を計算して返します.言い換えれば、この小数と唯一の上限を合わせて下に整数を取って+1を返します.
2つのパラメータがある場合:floor(r*(u-l+1)+lを計算して返します.意味は似ています.
C言語でrand()の前にsrand()にランダムシードを設定しないと、rand()が返すシーケンスは一定であり、例えば私のマシンでrand()が返す最初の値はずっと41であることを知っています.したがってluaにシードを設定せずに直接ランダムにすると、与えられた一意の上限比較が小さい場合、最初の値は決定され、例えば
math.random(100)
この結果は基本的に1であり、これまで種子が設定されていなかったため、上の生成過程に基づいて、私の機械でrand()を返すか41を返すかで、rは非常に小さいので、最初の値は1に等しいので、ランダムな範囲が非常に大きいとこのような状況から抜け出すことができ、同時にあなたも発見することができます.この場合、君がmathであろうとrandom(99)かmathか.random(101)の結果はいずれも1になります.理由は上記の通りです.
この場合、lua-userで与えられた解決策は、ランダムになる前にシードを設定し、最初の3つのランダム数を投げて、なぜ4つではなく3つなのか、私もなぜか分かりません....
同時に何を種子とするかも問題であり、一般的にランダム性の要求が高くないシステムにとって、通常はシステム時間を種子とすることができ、そこで私たちはこのように書くことができます.
しかし、ここにはもう一つの問題があります.osです.time()は短時間で変化が非常に小さく、システム時間は秒で増加し、一定時間で変化するのは最低数ビットであり、このコードを実行すると、プログラムを実行する間隔が大きくない場合、乱数は変化していないことがわかります.lua-userにもシナリオが与えられています.
意味はこのos.time()の数は秒で変わるのではないでしょうか.それを逆にして、このように秒が変動すれば、全体の数が非常に大きく変動し、後ろに上位6位を取ったのは、種子の変化レベルが10の5回になった後で明らかになるはずで、もっと大きな種子は必要ありません.
しかし、ここではもう一つの問題があります.彼が上位6位を切り取ったからこそ、長い時間が経った後、ここの種はまた繰り返し始めた可能性がありますが、このような状況に基づいて発生する確率は比較的小さく、繰り返しが発生しても全体的にランダム性に影響を与えないように見えるので、納得できます.
詳細は以下を参照してください.http://lua-users.org/wiki/MathLibraryTutorial
lua_Number r = (lua_Number)(rand()%RAND_MAX)/(lua_Number)RAND_MAX;
これは実は0~1の間の小数を生成し、mathに基づいている.randomのパラメータの個数で操作します.
パラメータがない場合はこの数を直接返します.もちろん、切断されます.
パラメータが1つある場合、floor(r*u)+1を計算して返します.言い換えれば、この小数と唯一の上限を合わせて下に整数を取って+1を返します.
2つのパラメータがある場合:floor(r*(u-l+1)+lを計算して返します.意味は似ています.
C言語でrand()の前にsrand()にランダムシードを設定しないと、rand()が返すシーケンスは一定であり、例えば私のマシンでrand()が返す最初の値はずっと41であることを知っています.したがってluaにシードを設定せずに直接ランダムにすると、与えられた一意の上限比較が小さい場合、最初の値は決定され、例えば
math.random(100)
この結果は基本的に1であり、これまで種子が設定されていなかったため、上の生成過程に基づいて、私の機械でrand()を返すか41を返すかで、rは非常に小さいので、最初の値は1に等しいので、ランダムな範囲が非常に大きいとこのような状況から抜け出すことができ、同時にあなたも発見することができます.この場合、君がmathであろうとrandom(99)かmathか.random(101)の結果はいずれも1になります.理由は上記の通りです.
この場合、lua-userで与えられた解決策は、ランダムになる前にシードを設定し、最初の3つのランダム数を投げて、なぜ4つではなく3つなのか、私もなぜか分かりません....
同時に何を種子とするかも問題であり、一般的にランダム性の要求が高くないシステムにとって、通常はシステム時間を種子とすることができ、そこで私たちはこのように書くことができます.
math.randomseed( os.time() )
math.random(); math.random(); math.random()
しかし、ここにはもう一つの問題があります.osです.time()は短時間で変化が非常に小さく、システム時間は秒で増加し、一定時間で変化するのは最低数ビットであり、このコードを実行すると、プログラムを実行する間隔が大きくない場合、乱数は変化していないことがわかります.lua-userにもシナリオが与えられています.
math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )
意味はこのos.time()の数は秒で変わるのではないでしょうか.それを逆にして、このように秒が変動すれば、全体の数が非常に大きく変動し、後ろに上位6位を取ったのは、種子の変化レベルが10の5回になった後で明らかになるはずで、もっと大きな種子は必要ありません.
しかし、ここではもう一つの問題があります.彼が上位6位を切り取ったからこそ、長い時間が経った後、ここの種はまた繰り返し始めた可能性がありますが、このような状況に基づいて発生する確率は比較的小さく、繰り返しが発生しても全体的にランダム性に影響を与えないように見えるので、納得できます.
詳細は以下を参照してください.http://lua-users.org/wiki/MathLibraryTutorial