history | TOP |
2005/12/28:作成
overview | TOP |
最初に。このページの内容に独自性はありません。完全無欠にパクリです。
翻訳もそのまま、本当にそのままやってるんでコメントなどもそのままです。おまけに思いっきりDelphi版の実装も見つけてしまったりして...
しかもそのソースを覗き見して
{$OVERFLOWCHECKS OFF} {$RANGECHECKS ON}
をソースに追加してます。やっぱりオーバーフローするよなぁというのもコレを見たことで胸をなでおろしてます。
コード | TOP |
(* =========================================================================== mt19937ar.c mt19937ar.cの使い方 (2002/1, 2004/2改訂) (略) =========================================================================== *) unit mt19937ar; {$OVERFLOWCHECKS OFF} {$RANGECHECKS ON} interface function GenRandInt32(): Cardinal; function GenRandInt31(): Integer; function GenRandReal1(): Double; function GenRandReal2(): Double; function GenRandReal3(): Double; function GenRandRes53(): Double; implementation // Period parameters const MERSENNE_TWISTER_N = 624; MERSENNE_TWISTER_M = 397; MERSENNE_TWISTER_MATRIX_A = $9908b0df; // constant vector a MERSENNE_TWISTER_UPPER_MASK = $80000000; // most significant w-r bits MERSENNE_TWISTER_LOWER_MASK = $7fffffff; // least significant r bits F_MASK = $FFFFFFFF; var // the array for the state vector (unsigned long) Mt: array[0..MERSENNE_TWISTER_N-1] of Cardinal; // mti==N+1 means mt[N] is not initialized Mti: Cardinal = MERSENNE_TWISTER_N + 1; //----------------------------------------------------------------------------- // initializes mt[N] with a seed (unsigned long) procedure InitGenRand(const Seed: Cardinal); begin Mt[0] := Seed and F_MASK; Mti := 1; while (Mti < MERSENNE_TWISTER_N) do begin Mt[Mti] := (1812433253 * (Mt[Mti-1] xor (Mt[Mti-1] shr 30)) + Mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto Mt[Mti] := Mt[Mti] and F_MASK; // for >32 bit machines Inc(Mti); end; end; //----------------------------------------------------------------------------- function Max(const A, B: Integer): Integer; begin if (A >= B) then Result := A else Result := B; end; //----------------------------------------------------------------------------- // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 procedure InitByArray(const Seeds: array of Cardinal); var i, j, k: Cardinal; SeedsLen: Cardinal; begin InitGenRand(19650218); i := 1; j := 0; SeedsLen := Length(Seeds); k := Max(SeedsLen, MERSENNE_TWISTER_N); while (k > 0) do begin Mt[i] := (Mt[i] xor ((Mt[i-1] xor (Mt[i-1] shr 30)) * 1664525)) + Seeds[j] + j; // non linear Mt[i] := Mt[i] and F_MASK; // for WORDSIZE > 32 machines Inc(i); Inc(j); if (i >= MERSENNE_TWISTER_N) then begin Mt[0] := Mt[MERSENNE_TWISTER_N-1]; i := 1; end; if (j >= SeedsLen) then begin j := 0; end; Dec(k); end; for k := MERSENNE_TWISTER_N - 1 downto 1 do begin Mt[i] := (Mt[i] xor ((Mt[i-1] xor (Mt[i-1] shr 30)) * 1566083941)) - i; // non linear Mt[i] := Mt[i] and F_MASK; // for WORDSIZE > 32 machines Inc(i); if (i >= MERSENNE_TWISTER_N) then begin Mt[0] := Mt[MERSENNE_TWISTER_N-1]; i := 1; end; end; // MSB is 1; assuring non-zero initial array Mt[0] := $80000000; end; //----------------------------------------------------------------------------- // generates a random number on [0,0xffffffff]-interval function GenRandInt32(): Cardinal; const // mag01[x] = x * MATRIX_A for x=0,1 MAG01: array[0..1] of Cardinal = (0, MERSENNE_TWISTER_MATRIX_A); var kk: Integer; begin // generate N words at one time if (Mti >= MERSENNE_TWISTER_N) then begin // if init_genrand() has not been called, if (Mti = MERSENNE_TWISTER_N + 1) then begin // a default initial seed is used InitGenRand(5489); end; kk := 0; while (kk < MERSENNE_TWISTER_N - MERSENNE_TWISTER_M) do begin Result := (Mt[kk] and MERSENNE_TWISTER_UPPER_MASK) or (Mt[kk+1] and MERSENNE_TWISTER_LOWER_MASK); Mt[kk] := Mt[kk + MERSENNE_TWISTER_M] xor (Result shr 1) xor MAG01[Result and 1]; Inc(kk); end; while (kk < MERSENNE_TWISTER_N - 1) do begin Result := (Mt[kk] and MERSENNE_TWISTER_UPPER_MASK) or (Mt[kk+1] and MERSENNE_TWISTER_LOWER_MASK); Mt[kk] := Mt[kk + (MERSENNE_TWISTER_M - MERSENNE_TWISTER_N)] xor (Result shr 1) xor MAG01[Result and 1]; Inc(kk); end; Result := (Mt[MERSENNE_TWISTER_N-1] and MERSENNE_TWISTER_UPPER_MASK) or (Mt[0] and MERSENNE_TWISTER_LOWER_MASK); Mt[MERSENNE_TWISTER_N-1] := Mt[MERSENNE_TWISTER_M-1] xor (Result shr 1) xor MAG01[Result and 1]; Mti := 0; end; Result := Mt[Mti]; Inc(Mti); // Tempering Result := Result xor (Result shr 11); Result := Result xor ((Result shl 7) and $9d2c5680); Result := Result xor ((Result shl 15) and $efc60000); Result := Result xor (Result shr 18); end; //----------------------------------------------------------------------------- // generates a random number on [0,0x7fffffff]-interval function GenRandInt31(): Integer; begin Result := (GenRandInt32() shr 1); end; //----------------------------------------------------------------------------- // generates a random number on [0,1]-real-interval function GenRandReal1(): Double; begin // divided by 2^32-1 Result := (GenRandInt32() * (1.0 / 4294967295.0)); end; //----------------------------------------------------------------------------- // generates a random number on [0,1)-real-interval function GenRandReal2(): Double; begin // divided by 2^32 Result := (GenRandInt32() * (1.0 / 4294967296.0)); end; //----------------------------------------------------------------------------- // generates a random number on (0,1)-real-interval function GenRandReal3(): Double; begin // divided by 2^32 Result := (GenRandInt32() + 0.5) * (1.0 / 4294967296.0); end; //----------------------------------------------------------------------------- // generates a random number on [0,1) with 53-bit resolution function GenRandRes53(): Double; var a, b: Cardinal; begin a := GenRandInt32() shr 5; b := GenRandInt32() shr 6; Result := (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); end; //----------------------------------------------------------------------------- const DefaultSeeds: array[0..3] of Cardinal = ($123, $234, $345, $456); initialization //InitGenRand(19650218); InitByArray(DefaultSeeds); end.
使い方 | TOP |
こんな感じで。これは本家が乱数出力サンプル(mt19937ar.out)を試験用に出しているんですが、それと同じ内容を出力するためのコードです。
uses mt19937ar; //----------------------------------------------------------------------------- // These real versions are due to Isaku Wada, 2002/01/09 added procedure TForm1.Button1Click(Sender: TObject); var i: Integer; c: Cardinal; r: double; FileName: String; FileStream: TFileStream; Line: String; begin FileName := ChangeFileExt(ParamStr(0), '.txt'); FileStream := TFileStream.Create( FileName, fmCreate or fmShareDenyWrite); for i := 0 to 999 do begin c := GenRandInt32(); Line := Format('%10u ', [c]); FileStream.Write(Line[1], Length(Line)); if (i mod 5 = 4) then begin Line := #13#10; FileStream.Write(Line[1], Length(Line)); end; end; for i := 0 to 999 do begin r := GenRandReal2(); Line := Format('%10.8f ', [r]); FileStream.Write(Line[1], Length(Line)); if (i mod 5 = 4) then begin Line := #13#10; FileStream.Write(Line[1], Length(Line)); end; end; FileStream.Free; Application.MessageBox(PChar(FileName + 'に出力完了'), PChar('情報'), MB_OK or MB_ICONINFORMATION); end;
実行結果・ダウンロード | TOP |
1067595299 955945823 477289528 4107218783 4228976476 (990個の整数乱数を略) 2643151863 3896204135 2416995901 1397735321 3460025646 0.76275443 0.99000644 0.98670464 0.10143112 0.27933125 (990個の実数乱数を略) 0.33163422 0.85739792 0.59908488 0.74566046 0.72157152
ちゃんとあってるようです。
20051227MersenneTwisterTest.zip(167,509bytes)
EOF | TOP |