PurePerlでメルセンヌ・ツイスタな話。Ver.0.1
レン鯖とかでの移植性を考えてPurePerlでメルセンヌ・ツイスターを実装してみようと言う話。
追記
404 Blog Not Found:perl - Math - Mersenne Twister を Pure Perlででバグ取りも含めて作りなおされたので、そちらを参照してください。
旧テキスト
☆Perlでメルセンヌ・ツイスタ | 徒然日記と言う先達がいらっしゃるのだが、実はここのソースはそのままコピペしただけでは動かないと言うミス。
これはご本人のせいではなくて、ソース中のビットシフト演算を意味する">>"がHTMLとして解釈されてしまって消えていて、それがコピーできずにそのまま実行するとSyntax errorを引き起こすのである。
それとまあ、ソースそのものが、C言語で書かれたhttp://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.cを直訳しただけで、Perl的なアレになってないと言うのもある。まさに機械翻訳。そりゃ、読むのは機械なんだけどさ。
なので、自分でhttp://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.cを読みながら(俺みたいな腐れPerlerでも、簡単なC言語くらいは読めるんだぜ?)、Perlに翻訳してみた。
MTpp.pm
文字コードはutf8Nだ!
package MTpp; use utf8; use strict; use integer; use bigint; # 日本語じゃよー。ぎゃわー。 sub N { return 624; } sub M { return 397; } sub MATRIX_A { return 0x9908b0df; } sub UPPER_MASK { return 0x80000000; } sub LOWER_MASK { return 0x7fffffff; } our @mt = (); our $mti = &N+1; sub init_genrand { my $s = shift; $mt[0] = $s & 0xffffffff; foreach my $mti ( 1..(&N-1) ) { $mt[$mti] = ( 1812433253 * ( $mt[$mti-1] ^ ( $mt[$mti-1] >> 30 ) ) + $mti ); $mt[$mti] &= 0xffffffff; } } sub genrand_int32 { my $y = undef; my @mag01 = ( 0, MATRIX_A ); unless ( $mti < &N ) { init_genrand(5489) if ( $mti == &N+1 ); foreach my $kk ( 0..( &N-&M ) ) { $y = ( $mt[$kk] & UPPER_MASK ) | ( $mt[$kk+1] & LOWER_MASK ); $mt[$kk] = $mt[$kk+&M] ^ ( $y >> 1 ) ^ $mag01[$y & 0x1]; } foreach my $kk ( ( &N-&M )..( &N-1 ) ) { $y = ( $mt[$kk] & UPPER_MASK ) | ( $mt[$kk+1] & LOWER_MASK ); $mt[$kk] = $mt[$kk+(&M-&N)] ^ ( $y >> 1 ) ^ $mag01[$y & 0x1]; } my $kk = &N - 1; $y = ( $mt[$kk] & UPPER_MASK ) | ( $mt[$kk+1] & LOWER_MASK ); $mt[&N-1] = $mt[&M-1] ^ ( $y >> 1 ) ^ $mag01[$y & 0x1]; $mti = 0; } $y = $mt[$mti++]; $y ^= ( $y >> 11 ); $y ^= ( $y << 7 ) & 0x9d2c5680; $y ^= ( $y << 15 ) & 0xefc60000; $y ^= ( $y >> 18 ); return $y; } 1;
使い方
&MTpp::init_genrand($seed);で初期化して、
&MTpp::genrand_int32();を呼びだす。
返り値として、0から2^32-1の範囲の整数が戻ってくるので、それを適当に料理して乱数として扱って!
テスト
あー、なんかそれっぽくなってるから大丈夫じゃないかな。
十万個の乱数を発生させて、65536で割って表にしてみたけど、まあ、適当に散らばって出たと思うんだ。
キモ
☆Perlでメルセンヌ・ツイスタ | 徒然日記にも書いてあるんだけど。
Perlは32ビット符号なし整数が扱えないのかっ!
これに対する解決として、use bigintプラグマの導入と言う激烈馬鹿な手段を選択してしまい、MTの利点である「高速性」を大きく損なうことに成功。ダメじゃん!
これからの展開
- bigintプラグマを使わない方向で頭を働かせる。
- OO化する。