github.com/gopherd/gonum@v0.0.4/mathext/prng/mt19937.go (about) 1 // Copyright ©2019 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Original C program copyright Takuji Nishimura and Makoto Matsumoto 2002. 6 // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c 7 8 package prng 9 10 import ( 11 "encoding/binary" 12 "io" 13 ) 14 15 const ( 16 mt19937N = 624 17 mt19937M = 397 18 mt19937matrixA = 0x9908b0df 19 mt19937UpperMask = 0x80000000 20 mt19937LowerMask = 0x7fffffff 21 ) 22 23 // MT19937 implements the 32 bit Mersenne Twister PRNG. MT19937 24 // is the default PRNG for a wide variety of programming systems. 25 // See https://en.wikipedia.org/wiki/Mersenne_Twister. 26 type MT19937 struct { 27 mt [mt19937N]uint32 28 mti uint32 29 } 30 31 // NewMT19937 returns a new MT19937 PRNG. The returned PRNG will 32 // use the default seed 5489 unless the Seed method is called with 33 // another value. 34 func NewMT19937() *MT19937 { 35 return &MT19937{mti: mt19937N + 1} 36 } 37 38 // Seed uses the provided seed value to initialize the generator to a 39 // deterministic state. Only the lower 32 bits of seed are used to seed 40 // the PRNG. 41 func (src *MT19937) Seed(seed uint64) { 42 src.mt[0] = uint32(seed) 43 for src.mti = 1; src.mti < mt19937N; src.mti++ { 44 src.mt[src.mti] = (1812433253*(src.mt[src.mti-1]^(src.mt[src.mti-1]>>30)) + src.mti) 45 } 46 } 47 48 // SeedFromKeys uses the provided seed key value to initialize the 49 // generator to a deterministic state. It is provided for compatibility 50 // with C implementations. 51 func (src *MT19937) SeedFromKeys(keys []uint32) { 52 src.Seed(19650218) 53 i := uint32(1) 54 j := uint32(0) 55 k := uint32(mt19937N) 56 if k <= uint32(len(keys)) { 57 k = uint32(len(keys)) 58 } 59 for ; k != 0; k-- { 60 src.mt[i] = (src.mt[i] ^ ((src.mt[i-1] ^ (src.mt[i-1] >> 30)) * 1664525)) + keys[j] + j // Non linear. 61 i++ 62 j++ 63 if i >= mt19937N { 64 src.mt[0] = src.mt[mt19937N-1] 65 i = 1 66 } 67 if j >= uint32(len(keys)) { 68 j = 0 69 } 70 } 71 for k = mt19937N - 1; k != 0; k-- { 72 src.mt[i] = (src.mt[i] ^ ((src.mt[i-1] ^ (src.mt[i-1] >> 30)) * 1566083941)) - i // Non linear. 73 i++ 74 if i >= mt19937N { 75 src.mt[0] = src.mt[mt19937N-1] 76 i = 1 77 } 78 } 79 src.mt[0] = 0x80000000 // MSB is 1; assuring non-zero initial array. 80 } 81 82 // Uint32 returns a pseudo-random 32-bit unsigned integer as a uint32. 83 func (src *MT19937) Uint32() uint32 { 84 mag01 := [2]uint32{0x0, mt19937matrixA} 85 86 var y uint32 87 if src.mti >= mt19937N { // Generate mt19937N words at one time. 88 if src.mti == mt19937N+1 { 89 // If Seed() has not been called 90 // a default initial seed is used. 91 src.Seed(5489) 92 } 93 94 var kk int 95 for ; kk < mt19937N-mt19937M; kk++ { 96 y = (src.mt[kk] & mt19937UpperMask) | (src.mt[kk+1] & mt19937LowerMask) 97 src.mt[kk] = src.mt[kk+mt19937M] ^ (y >> 1) ^ mag01[y&0x1] 98 } 99 for ; kk < mt19937N-1; kk++ { 100 y = (src.mt[kk] & mt19937UpperMask) | (src.mt[kk+1] & mt19937LowerMask) 101 src.mt[kk] = src.mt[kk+(mt19937M-mt19937N)] ^ (y >> 1) ^ mag01[y&0x1] 102 } 103 y = (src.mt[mt19937N-1] & mt19937UpperMask) | (src.mt[0] & mt19937LowerMask) 104 src.mt[mt19937N-1] = src.mt[mt19937M-1] ^ (y >> 1) ^ mag01[y&0x1] 105 106 src.mti = 0 107 } 108 109 y = src.mt[src.mti] 110 src.mti++ 111 112 // Tempering. 113 y ^= (y >> 11) 114 y ^= (y << 7) & 0x9d2c5680 115 y ^= (y << 15) & 0xefc60000 116 y ^= (y >> 18) 117 118 return y 119 } 120 121 // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. 122 // It makes use of two calls to Uint32 placing the first result in the 123 // upper bits and the second result in the lower bits of the returned 124 // value. 125 func (src *MT19937) Uint64() uint64 { 126 h := uint64(src.Uint32()) 127 l := uint64(src.Uint32()) 128 return h<<32 | l 129 } 130 131 // MarshalBinary returns the binary representation of the current state of the generator. 132 func (src *MT19937) MarshalBinary() ([]byte, error) { 133 var buf [(mt19937N + 1) * 4]byte 134 for i := 0; i < mt19937N; i++ { 135 binary.BigEndian.PutUint32(buf[i*4:(i+1)*4], src.mt[i]) 136 } 137 binary.BigEndian.PutUint32(buf[mt19937N*4:], src.mti) 138 return buf[:], nil 139 } 140 141 // UnmarshalBinary sets the state of the generator to the state represented in data. 142 func (src *MT19937) UnmarshalBinary(data []byte) error { 143 if len(data) < (mt19937N+1)*4 { 144 return io.ErrUnexpectedEOF 145 } 146 for i := 0; i < mt19937N; i++ { 147 src.mt[i] = binary.BigEndian.Uint32(data[i*4 : (i+1)*4]) 148 } 149 src.mti = binary.BigEndian.Uint32(data[mt19937N*4:]) 150 return nil 151 }