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  }