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 に書くと,「シンボルが解決できない」ためその関数を利用できなかった.確かにオブジェクト化したものを呼び出しては「インライン展開」でなく,普通の関数呼び出しとなる.

今日,インライン関数を書く場所が分かった.