XorShift の C++ クラスを作ってみた
rand() の結果は奇遇が順序よく出るとか,線形だとかで,ランダムが欲しいときは別のアルゴリズムを利用するべきらしい.どこかで Mersenne Twister が推奨されていたが,簡単に利用する方法が分からなかった.簡単そうなのが XorShift で,試してみて,さくっと利用できた.
参考資料
コード
- Xorshift.h
- クラス定義
- XorShift.cpp
- インライン関数だけなので,存在意義はない
- main.cpp
- AES 暗号に用いるパスワード生成への利用例
Xorshift.h
// http://www001.upp.so-net.ne.jp/isaku/rand.html // http://ogawa-sankinkoutai.seesaa.net/article/108848981.html class Xorshift{ unsigned int gSeed128[4]; public: Xorshift( void ); // s には time( NULL ) または time( NULL ) * getpid() inline Xorshift( unsigned int s ); unsigned int xor128( void ); unsigned int fxor128( void ); }; __inline Xorshift::Xorshift( void ) { gSeed128[0] = 123456789U; gSeed128[1] = 362436069U; gSeed128[2] = 521288629U; gSeed128[3] = 88675123U; } // s には time( NULL ) または time( NULL ) * _getpid() // time(): time.h // _getpid(): process.h __inline Xorshift::Xorshift( unsigned int s ) { for( int i = 1; i <= 4; i++ ) { gSeed128[ i - 1 ] = s = 1812433253U * ( s ^ ( s >> 30 ) ) + i; } } __inline unsigned int Xorshift::xor128(void) { unsigned int t=gSeed128[0]^(gSeed128[0]<<11); gSeed128[0]=gSeed128[1]; gSeed128[1]=gSeed128[2]; gSeed128[2]=gSeed128[3]; return gSeed128[3]^=(gSeed128[3]>>19)^t^(t>>8); } __inline unsigned int Xorshift::fxor128( void ) { // http://www001.upp.so-net.ne.jp/isaku/rand.html /* 機械語命令とCのステートメントを1対1にした Xorshift。*/ /* 一見無駄に見えるが、こちらのほうが速いことが多い。*/ unsigned int t=gSeed128[0],r=t; t<<=11; t^=r; r=t; r>>=8; t^=r; r=gSeed128[1]; gSeed128[0]=r; r=gSeed128[2]; gSeed128[1]=r; r=gSeed128[3]; gSeed128[2]=r; t^=r; r>>=19; r^=t; gSeed128[3]=r; return r; }
Xorshift.cpp
#include "Xorshift.h"
main.cpp
#include <stdio.h> #include <process.h> #include <time.h> #include "Xorshift.h" #define numof(array) (sizeof(array)/sizeof(array[0])) int main(void) { unsigned char password[16]; Xorshift xos( (int)time(NULL)* _getpid() ); for(int n = 0; n < numof(password); n++) { printf("0x%0X\n", password[n] = (unsigned char)xos.fxor128()); } return 0; }
備考
インライン関数を Xorshift.cpp に書くと,「シンボルが解決できない」ためその関数を利用できなかった.確かにオブジェクト化したものを呼び出しては「インライン展開」でなく,普通の関数呼び出しとなる.
今日,インライン関数を書く場所が分かった.