乱数の使い方
k.inabaさんに久々に絡んでみようと思う。
http://www.kmonos.net/wlog/97.html#_2206090523
http://www001.upp.so-net.ne.jp/isaku/rand.html
さらに、初期化ミスのため、例えば以下のプログラムを JAVA で実行すると、
public class RandTest { static java.util.Random r=new java.util.Random(); public static void main (String[] args) { double x,Min=1,Max=0; for (int i=0;i<1024;i++) { r.setSeed(i); x=r.nextDouble(); if (x>Max) Max=x; if (x結果は、
Min=0.6753377750582709 Max=0.7669794809891215
となり、0から1023までの種で初期化したにもかかわらず、最初の乱数は0.7近辺しか現われない。
このサイトなんかでは、メルセンヌツイスタを使いましょう、とのことなんだけども、そもそもこの実験って意味無いんですけどー。乱数のSeedを、いくつも与えてみました、というのはそもそも乱数の使い方を間違っています。Seed1とSeed2という二つのSeedを与えたときの乱数が、互いに無相関である保障はほとんどの乱数で存在していません。それはメルセンヌツイスタでも一緒。
だから例えば、モンテカルロ実験を並列に実行しようとしたときに、マシン1..マシンnで、別のSeedを用いて計算すればよい、と単純に考えてはいけません。場合によれば、マシン1のn項目とマシン2のn+1項目が常に一緒、みたいな乱数が生成されるかもしれません。もしそうすれば、この実験は適切に並列化できていないことになり、結果として期待されている精度が出ないことになります。この危険性は、例え初期Seedとして自然乱数を使ったとしても、常に起こりえます。
では、こういった問題にどう対処するべきか、といえば、通常はその内部アルゴリズム上、絶対にかぶらないようなSeedを複数用意します。例えば、線形合同法で周期が100M程度であれば、マシン1には適当なものを、マシン2にはこのSeedから10M回生成を行った後の値を、・・・・マシン10には90M回生成を行った後の値を、とやります。そしてこの方法は、メルセンヌツイスタの場合も大体同じです。
自分で書きたくない場合は、こんなものがあります(SPRNG: http://sprng.cs.fsu.edu/)。
で、メルセンヌツイスタも同じ問題を抱えているのに、なぜメルセンヌツイスタではあまりその問題が観測されないのか。それは、1.メルセンヌツイスタはアルゴリズムが複雑で解析しにくく、2.周期が長いのでSeedによって偶然かぶることが比較的少なく、3.宗教的にもメルセンヌツイスタは正しいと思われているから、です。用法用量を守って正しく使いましょう。