' 書き込んだ後、uFix は必要がないことに気づきました。 ' こっちの方が高速です。 Option Explicit Public x, y, z, w As Double
Function uXor(ByVal i As Double, ByVal j As Double) As Double Const Base = 2# ^ 30 Dim u, v As Long u = Int(i / Base): v = Int(j / Base): i = i - u * Base: j = j - v * Base uXor = (u Xor v) * Base + (Int(i) Xor Int(j)) End Function
Function xor128() As Double Dim t As Double t = x * 2# ^ 11: t = t - Int(t / 2# ^ 32) * 2# ^ 32 t = uXor(x, t): x = y: y = z: z = w: t = uXor(t, Int(t / 2# ^ 8)) w = uXor(uXor(w, Int(w / 2# ^ 19)), t): xor128 = w End Function
Sub Test() Dim i As Long x = 123456789#: y = 362436069#: z = 521288629#: w = 88675123# For i = 1 To 2000: Cells(i, 1) = xor128: Next End Sub
'種を使って初期化できます。116よりさらに2倍程度高速になりました Private Const p32 = 2# ^ 32, p31 = 2# ^ 31, p21 = 2# ^ 21, p11 = 2# ^ 11 Private Const m53 = 2# ^ -53, m32 = 2# ^ -32, m30 = 2# ^ -30, m19 = 2# ^ -19, m11 = 2# ^ -11, m8 = 2# ^ -8 Private x, y, z, w As Double Private f As Boolean Private Function uXor(ByVal x As Double, ByVal y As Double) As Double Dim u, v As Long If x >= p31 Then u = x - p32 Else u = x If y >= p31 Then v = y - p32 Else v = y u = u Xor v If u < 0 Then uXor = u + p32 Else uXor = u End Function Private Function XSub(ByVal x As Double, ByVal i As Long) As Double Dim s As Variant s = CDec(1812433253) * CDec(uXor(x, Int(x * m30))) + CDec(i): s = s - CDec(Int(s * m32)) * CDec(p32): XSub = s End Function Public Sub InitXor(ByVal s As Long) ' s を種にして乱数を初期化する f = True: x = XSub(s, 1): y = XSub(x, 2): z = XSub(y, 3): w = XSub(z, 4) End Sub Private Function NextXor() As Double Dim t As Double If f = 0 Then InitXor (1) t = x * p11: t = t - Int(t * m32) * p32: t = uXor(x, t): x = y: y = z: z = w: t = uXor(t, Int(t * m8)): w = uXor(uXor(w, Int(w * m19)), t): NextXor = w End Function Public Function NextUnif() As Double ' 0 以上 1 未満の乱数を返す Dim x, y As Double x = NextXor * m11: y = NextXor: NextUnif = (y * p21 + Int(x)) * m53 End Function
MTならFORTRANだけど ttp://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/fortran.html この中に revrand(): it generates prn in reverse order って書いてあるけど
#define main dummy #include "mt19937ar.c" #undef main
unsigned long revgrnd(void) { static unsigned long mag01[2]={0x0UL,MATRIX_A}; unsigned long y=mt[--mti],z,p,q,mt0L,mt0; int x,kk; if (mti==0) { z=mt[N-1]^mt[M-1]; x=(int)(z>>31); y=z^mag01[x]; p=(y<<1)|x; mt0L=LOWER_MASK&p; mt[0]=(mt[0]&UPPER_MASK)^mt0L; mt0=mt[0]; for (kk=N-1;kk>N-M;kk--) { z=mt[kk-1]^mt[kk-1+M-N]; x=(int)(z>>31); y=z^mag01[x]; q=(y<<1)|x; mt[kk]=(UPPER_MASK&p)|(LOWER_MASK&q); p=q; } for (;kk;kk--) { z=mt[kk-1]^mt[kk-1+M]; x=(int)(z>>31); y=z^mag01[x]; q=(y<<1)|x; mt[kk]=(UPPER_MASK&p)|(LOWER_MASK&q); p=q; } mt[0]=(UPPER_MASK&p)|mt0L; y=mt0; mti=N; } y^=(y>>11); y^=(y<<7)&0x9d2c5680UL; y^=(y<<15)&0xefc60000UL; y^=(y>>18); return y; }
int main(void) { int i; static unsigned long x[5000],y[5000]; for (i=0;i<5000;i++) x[i]=genrand_int32(); for (i=4999;i>=0;i--) y[i]=revgrnd(); for (i=0;i<5000;i++) if (x[i]!=y[i]) { printf("ERROR\n"); break; } for (i=0;i<10;i++) printf("%08lx %08lx\n",x[i],y[i]); return 0; }