10年以上前に書いたツイスターの改造版が見つかったので掲載します。GPLとかBSDとかのライセンスはよくわからないので、もし、この公開が問題あるようならご指摘くださいm(_ _)m
主な改造内容はコメントを見ていただければわかりますが、オリジナルの実装だと最初に作った乱数を使い果たすとすべてを再度作る様になっています。これでは実使用上、不特定のタイミングで大きなオーバーヘッドが生じることになってしまいます。
そこで乱数を使用するごとに次周の分を作成するようにしました。これにより実運用上は大きなオーバーヘッドの変化が生じないと思います。
Twister.h
#if !defined(AFX_TWISTER_H__7CBE0C01_D79E_11D2_A3E1_00606733955B__INCLUDED_)
#define AFX_TWISTER_H__7CBE0C01_D79E_11D2_A3E1_00606733955B__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
//====================================================================
//====================================================================
//====================================================================
//
// Twister.h: CTwister クラスのインターフェイス
//
//====================================================================
//====================================================================
//====================================================================
class CTwister
{
//================================================================
//=== 構築/消滅 ==================================================
//================================================================
public:
CTwister();
//================================================================
//=== アトリビュート (定数) ======================================
//================================================================
protected:
enum {
N = 624, // データースロット数
M = 397, // インターリブ長
MATRIX_A = 0x9908b0df, // constant vector a
UPPER_MASK = 0x80000000, // most significant w-r bits
LOWER_MASK = 0x7fffffff, // least significant r bits
TEMPERING_MASK_B = 0x9d2c5680,
TEMPERING_MASK_C = 0xefc60000,
};
//================================================================
//=== アトリビュート (変数) ======================================
//================================================================
protected:
DWORD m_dwlData[N+M];
int m_iCurPos;
//================================================================
//=== アトリビュート (関数) ======================================
//================================================================
protected:
DWORD dwGetData( int iIndex )
{ return m_dwlData[(iIndex) % (N+M)]; }
DWORD dwCreateNew( int iPos );
DWORD dwTemperingShiftU( DWORD dw )
{ return dw >> 11; }
DWORD dwTemperingShiftS( DWORD dw )
{ return (dw << 7) & (DWORD)TEMPERING_MASK_B; }
DWORD dwTemperingShiftT( DWORD dw )
{ return (dw << 15) & (DWORD)TEMPERING_MASK_C; }
DWORD dwTemperingShiftL( DWORD dw )
{ return dw >> 18; }
//================================================================
//=== オペレーション =============================================
//================================================================
public:
void Randomize( DWORD dwSeed = 0 );
DWORD dwRandom( );
int iRandom( )
{ return (int)dwRandom( ); }
WORD wRandom( )
{ return (WORD)dwRandom( ); }
DWORD dwRandom( DWORD dwLimit );
int iRandom( int iLimit )
{ return (int)dwRandom( (DWORD)iLimit ); }
protected:
void SetData( int iIndex, DWORD dwData )
{ m_dwlData[(iIndex) % (N+M)] = dwData; }
};
//====================================================================
//====================================================================
//====================================================================
#endif // !defined(AFX_TWISTER_H__7CBE0C01_D79E_11D2_A3E1_00606733955B__INCLUDED_)
Twister.cpp
//====================================================================
//====================================================================
//====================================================================
//
// Twister.cpp : CTwisterインプリメンテーション ファイル
//
// 元のアルゴリズムでは、一度に全スロットにデーターを設定し、使い終わ
// ったらまた全スロット再設定するようになっていたが、これでは、処理速
// 度が変化してしまい使いにくいので、1つ使うごとに次週のデーターを作
// 成するように修正しました。
//
// この修正のためデーターバッファのサイズが2倍になってしまいました。
//
//====================================================================
//====================================================================
//====================================================================
#include "stdafx.h"
#include "Twister.h"
//=== ヘッダー・ファイル・インクルード ===============================
//=== インライン関数インクルード =====================================
//====================================================================
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//====================================================================
//=== tempering parameters ===========================================
//====================================================================
//====================================================================
//=== 構築 ===========================================================
//====================================================================
CTwister::CTwister()
{
Randomize( 4357/*0*/ );
}
//====================================================================
//=== 新たなデーターの作成 ===========================================
//====================================================================
inline DWORD CTwister::dwCreateNew( int iPos )
{
DWORD dw0 = dwGetData( iPos );
DWORD dw1 = dwGetData( iPos + 1 );
DWORD dwM = dwGetData( iPos + M );
DWORD dw = (dw0 & (DWORD)UPPER_MASK) | (dw1 & (DWORD)LOWER_MASK);
dw = dwM ^ (dw >> 1) ^ ((dw & 1) ? MATRIX_A : 0);
return dw;
}
//====================================================================
//=== 乱数初期化 =====================================================
//====================================================================
void CTwister::Randomize( DWORD dwSeed/* = 0*/ )
{
if ( dwSeed )
m_dwlData[0] = dwSeed & 0xffffffff;
else
m_dwlData[0] = ::GetTickCount( );
//================================================================
for ( m_iCurPos = 1 ; m_iCurPos < N ; ++ m_iCurPos )
m_dwlData[m_iCurPos] = ( 69069 * m_dwlData[m_iCurPos-1] ) & 0xffffffff;
//================================================================
for ( int i = 0 ; i < N ; ++ i )
{
DWORD dw = dwCreateNew( i );
SetData( i, dw );
}
//================================================================
m_iCurPos = 0;
}
//====================================================================
//=== 乱数発生 =======================================================
//====================================================================
DWORD CTwister::dwRandom( )
{
//================================================================
//=== 今回の乱数を生成 ===========================================
//================================================================
DWORD dwRet = m_dwlData[m_iCurPos];
//=== +M 位置の作成のため今回の値を保存 ==========================
SetData( m_iCurPos + N, dwRet );
//=== 乱数作成 ===================================================
dwRet ^= dwTemperingShiftU(dwRet);
dwRet ^= dwTemperingShiftS(dwRet);
dwRet ^= dwTemperingShiftT(dwRet);
dwRet ^= dwTemperingShiftL(dwRet);
//================================================================
//=== 次周の為のデーターを作成 ===================================
//================================================================
DWORD dw = dwCreateNew( m_iCurPos );
SetData( m_iCurPos + N, dw );
//================================================================
//================================================================
//================================================================
m_iCurPos = (m_iCurPos + 1) % (N + M);
//================================================================
//================================================================
//================================================================
return dwRet;
}
//====================================================================
//=== 引数未満の乱数を発生 ===========================================
//====================================================================
//DWORD CTwister::dwRandom( DWORD dwLimit )
//{
// return (int)(((__int64)dwRandom() * (__int64)dwLimit) >> 32);
//}
//
#pragma warning(disable : 4035)
DWORD CTwister::dwRandom( DWORD dwLimit )
{
dwRandom( );
__asm
{
MUL [dwLimit]
MOV EAX, EDX
}
}
#pragma warning(default : 4035)
//====================================================================
//=== オリジナルです =================================================
//====================================================================
//
//DWORD CTwister::dwRandom( )
//{
// DWORD y;
// static DWORD mag01[2] = {0x0, MATRIX_A};
//
// if ( m_iCurPos >= N )
// {
// /* generate N words at one time */
// int kk;
//
// if ( m_iCurPos == N+1 ) /* if sgenrand() has not been called, */
// Randomize( 4357 ); /* a default initial seed is used */
//
// for (kk=0;kk> 1) ^ mag01[y & 0x1];
// }
//
// for (;kk> 1) ^ mag01[y & 0x1];
// }
//
// y = (m_dwlData[N-1]&UPPER_MASK) | (m_dwlData[0]&LOWER_MASK);
// m_dwlData[N-1] = m_dwlData[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
//
// m_iCurPos = 0;
// }
//
// y = m_dwlData[m_iCurPos++];
// y ^= TEMPERING_SHIFT_U(y);
// y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
// y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
// y ^= TEMPERING_SHIFT_L(y);
//
// return y;
//}