github.com/xaionaro-go/rand@v0.0.0-20191005105903-aba1befc54a5/mathrand/prng.go (about)

     1  package mathrand
     2  
     3  import "time"
     4  
     5  var (
     6  	// GlobalPRNG is just an initialized (ready-to-use) PRNG which could
     7  	// be used from anywhere.
     8  	GlobalPRNG = New()
     9  )
    10  
    11  // PRNG is a instance of a pseudo-mathrandom number generator.
    12  type PRNG struct {
    13  	state64  [4]uint64
    14  	state32  [4]uint32
    15  	pcgState uint64
    16  }
    17  
    18  // New creates new instance of pseudo-mathrandom number generator.
    19  //
    20  // Methods of PRNG are not thread-safe in formal terms (which is usually
    21  // not important for an PRNG) and it sometimes may return the same value to
    22  // concurrent routines. If you need a non-copy guarantee among concurrent
    23  // calls of a method (for example for "nonce") then you can use different
    24  // instances of mathrand.PRNG for different goroutines. Also if you use a
    25  // random number for example for sampling then you can safely use this
    26  // function (because such errors won't make any negative effect to your
    27  // application).
    28  //
    29  // And example for multiple goroutines:
    30  //
    31  // 	var prngPool = sync.Pool{New: func() interface{}{ return mathrand.New() }}
    32  // 	...
    33  // 	prng := prngPool.Get().(*mathrand.PRNG).
    34  // 	prng.ReadUint64Xoshiro256(b)
    35  //  prngPoo.Put(prng)
    36  //
    37  // Note: Random numbers of this PRNG could easily be predicted (it's not an
    38  // analog of crypto/rand).
    39  func New() *PRNG {
    40  	return NewWithSeed(uint64(time.Now().UnixNano()))
    41  }
    42  
    43  // NewWithSeed is the same as `New` but initializes the PRNG with predefined
    44  // seed.
    45  func NewWithSeed(seed uint64) *PRNG {
    46  	prng := &PRNG{}
    47  	prng.SetSeed(seed)
    48  	return prng
    49  }
    50  
    51  func (prng *PRNG) SetSeed(seed uint64) {
    52  	i := uint64(0)
    53  	if seed == 0 {
    54  		seed = primeNumber64bit1
    55  	}
    56  	for idx := range prng.state64 {
    57  		prng.state64[idx] = seed
    58  		seed *= primeNumber64bit0
    59  		if prng.state64[idx] == 0 {
    60  			panic(`"seed+i" cannot be zero`)
    61  		}
    62  		i++
    63  	}
    64  	for idx := range prng.state32 {
    65  		prng.state32[idx] = uint32(seed)
    66  		seed *= primeNumber64bit0
    67  		if prng.state32[idx] == 0 {
    68  			panic(`"uint32(seed+i)" cannot be zero`)
    69  		}
    70  		i++
    71  	}
    72  	prng.pcgState = (seed << 1) + 1 // must be odd
    73  }
    74  
    75  func (prng *PRNG) Reseed() {
    76  	prng.SetSeed(prng.Uint64Xoshiro256())
    77  }
    78  
    79  func (prng *PRNG) fastReseed64() {
    80  	prng.state64[0] = prng.Uint64Xoshiro256()
    81  }
    82  
    83  func (prng *PRNG) fastReseed32() {
    84  	prng.state32[0] = uint32(prng.Uint64Xoshiro256())
    85  }
    86  
    87  func xorShift64(a uint64) uint64 {
    88  	a ^= a << 13
    89  	a ^= a >> 7
    90  	a ^= a << 17
    91  	return a
    92  }
    93  
    94  func xorShift32(a uint32) uint32 {
    95  	a ^= a << 13
    96  	a ^= a >> 17
    97  	a ^= a << 5
    98  	return a
    99  }