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 }