gonum.org/v1/gonum@v0.14.0/mathext/prng/prng_di_unimi.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 // PRNGs from Dipartimento di Informatica Università degli Studi di Milano. 6 // David Blackman and Sebastiano Vigna licensed under CC0 1.0 7 // http://creativecommons.org/publicdomain/zero/1.0/ 8 9 package prng 10 11 import ( 12 "encoding/binary" 13 "io" 14 "math/bits" 15 ) 16 17 // SplitMix64 is the splitmix64 PRNG from http://prng.di.unimi.it/splitmix64.c. 18 // The zero value is usable directly. SplitMix64 is primarily provided to support 19 // seeding the xoshiro PRNGs. 20 type SplitMix64 struct { 21 state uint64 22 } 23 24 // NewSplitMix64 returns a new pseudo-random splitmix64 source seeded 25 // with the given value. 26 func NewSplitMix64(seed uint64) *SplitMix64 { 27 var src SplitMix64 28 src.Seed(seed) 29 return &src 30 } 31 32 // Seed uses the provided seed value to initialize the generator to a 33 // deterministic state. 34 func (src *SplitMix64) Seed(seed uint64) { 35 src.state = seed 36 } 37 38 // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. 39 func (src *SplitMix64) Uint64() uint64 { 40 src.state += 0x9e3779b97f4a7c15 41 z := src.state 42 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9 43 z = (z ^ (z >> 27)) * 0x94d049bb133111eb 44 return z ^ (z >> 31) 45 } 46 47 // MarshalBinary returns the binary representation of the current state of the generator. 48 func (src *SplitMix64) MarshalBinary() ([]byte, error) { 49 var buf [8]byte 50 binary.BigEndian.PutUint64(buf[:], src.state) 51 return buf[:], nil 52 } 53 54 // UnmarshalBinary sets the state of the generator to the state represented in data. 55 func (src *SplitMix64) UnmarshalBinary(data []byte) error { 56 if len(data) < 8 { 57 return io.ErrUnexpectedEOF 58 } 59 src.state = binary.BigEndian.Uint64(data) 60 return nil 61 } 62 63 // Xoshiro256plus is the xoshiro256+ 1.0 PRNG from http://prng.di.unimi.it/xoshiro256plus.c. 64 // The xoshiro PRNGs are described in http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf 65 // and http://prng.di.unimi.it/. 66 // A Xoshiro256plus value is only valid if returned by NewXoshiro256plus. 67 type Xoshiro256plus struct { 68 state [4]uint64 69 } 70 71 // NewXoshiro256plus returns a new pseudo-random xoshiro256+ source 72 // seeded with the given value. 73 func NewXoshiro256plus(seed uint64) *Xoshiro256plus { 74 var src Xoshiro256plus 75 src.Seed(seed) 76 return &src 77 } 78 79 // Seed uses the provided seed value to initialize the generator to a 80 // deterministic state. 81 func (src *Xoshiro256plus) Seed(seed uint64) { 82 var boot SplitMix64 83 boot.Seed(seed) 84 for i := range src.state { 85 src.state[i] = boot.Uint64() 86 } 87 } 88 89 // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. 90 func (src *Xoshiro256plus) Uint64() uint64 { 91 result := src.state[0] + src.state[3] 92 93 t := src.state[1] << 17 94 95 src.state[2] ^= src.state[0] 96 src.state[3] ^= src.state[1] 97 src.state[1] ^= src.state[2] 98 src.state[0] ^= src.state[3] 99 100 src.state[2] ^= t 101 102 src.state[3] = bits.RotateLeft64(src.state[3], 45) 103 104 return result 105 } 106 107 // MarshalBinary returns the binary representation of the current state of the generator. 108 func (src *Xoshiro256plus) MarshalBinary() ([]byte, error) { 109 var buf [32]byte 110 for i := 0; i < 4; i++ { 111 binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.state[i]) 112 } 113 return buf[:], nil 114 } 115 116 // UnmarshalBinary sets the state of the generator to the state represented in data. 117 func (src *Xoshiro256plus) UnmarshalBinary(data []byte) error { 118 if len(data) < 32 { 119 return io.ErrUnexpectedEOF 120 } 121 for i := 0; i < 4; i++ { 122 src.state[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) 123 } 124 return nil 125 } 126 127 // Xoshiro256plusplus is the xoshiro256++ 1.0 PRNG from http://prng.di.unimi.it/xoshiro256plusplus.c. 128 // The xoshiro PRNGs are described in http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf 129 // and http://prng.di.unimi.it/. 130 // A Xoshiro256plusplus value is only valid if returned by NewXoshiro256plusplus. 131 type Xoshiro256plusplus struct { 132 state [4]uint64 133 } 134 135 // NewXoshiro256plusplus returns a new pseudo-random xoshiro256++ source 136 // seeded with the given value. 137 func NewXoshiro256plusplus(seed uint64) *Xoshiro256plusplus { 138 var src Xoshiro256plusplus 139 src.Seed(seed) 140 return &src 141 } 142 143 // Seed uses the provided seed value to initialize the generator to a 144 // deterministic state. 145 func (src *Xoshiro256plusplus) Seed(seed uint64) { 146 var boot SplitMix64 147 boot.Seed(seed) 148 for i := range src.state { 149 src.state[i] = boot.Uint64() 150 } 151 } 152 153 // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. 154 func (src *Xoshiro256plusplus) Uint64() uint64 { 155 result := bits.RotateLeft64(src.state[0]+src.state[3], 23) + src.state[0] 156 157 t := src.state[1] << 17 158 159 src.state[2] ^= src.state[0] 160 src.state[3] ^= src.state[1] 161 src.state[1] ^= src.state[2] 162 src.state[0] ^= src.state[3] 163 164 src.state[2] ^= t 165 166 src.state[3] = bits.RotateLeft64(src.state[3], 45) 167 168 return result 169 } 170 171 // MarshalBinary returns the binary representation of the current state of the generator. 172 func (src *Xoshiro256plusplus) MarshalBinary() ([]byte, error) { 173 var buf [32]byte 174 for i := 0; i < 4; i++ { 175 binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.state[i]) 176 } 177 return buf[:], nil 178 } 179 180 // UnmarshalBinary sets the state of the generator to the state represented in data. 181 func (src *Xoshiro256plusplus) UnmarshalBinary(data []byte) error { 182 if len(data) < 32 { 183 return io.ErrUnexpectedEOF 184 } 185 for i := 0; i < 4; i++ { 186 src.state[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) 187 } 188 return nil 189 } 190 191 // Xoshiro256starstar is the xoshiro256** 1.0 PRNG from http://prng.di.unimi.it/xoshiro256starstar.c. 192 // The xoshiro PRNGs are described in http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf 193 // and http://prng.di.unimi.it/. 194 // A Xoshiro256starstar value is only valid if returned by NewXoshiro256starstar. 195 type Xoshiro256starstar struct { 196 state [4]uint64 197 } 198 199 // NewXoshiro256starstar returns a new pseudo-random xoshiro256** source 200 // seeded with the given value. 201 func NewXoshiro256starstar(seed uint64) *Xoshiro256starstar { 202 var src Xoshiro256starstar 203 src.Seed(seed) 204 return &src 205 } 206 207 // Seed uses the provided seed value to initialize the generator to a 208 // deterministic state. 209 func (src *Xoshiro256starstar) Seed(seed uint64) { 210 var boot SplitMix64 211 boot.Seed(seed) 212 for i := range src.state { 213 src.state[i] = boot.Uint64() 214 } 215 } 216 217 // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. 218 func (src *Xoshiro256starstar) Uint64() uint64 { 219 result := bits.RotateLeft64(src.state[1]*5, 7) * 9 220 221 t := src.state[1] << 17 222 223 src.state[2] ^= src.state[0] 224 src.state[3] ^= src.state[1] 225 src.state[1] ^= src.state[2] 226 src.state[0] ^= src.state[3] 227 228 src.state[2] ^= t 229 230 src.state[3] = bits.RotateLeft64(src.state[3], 45) 231 232 return result 233 } 234 235 // MarshalBinary returns the binary representation of the current state of the generator. 236 func (src *Xoshiro256starstar) MarshalBinary() ([]byte, error) { 237 var buf [32]byte 238 for i := 0; i < 4; i++ { 239 binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], src.state[i]) 240 } 241 return buf[:], nil 242 } 243 244 // UnmarshalBinary sets the state of the generator to the state represented in data. 245 func (src *Xoshiro256starstar) UnmarshalBinary(data []byte) error { 246 if len(data) < 32 { 247 return io.ErrUnexpectedEOF 248 } 249 for i := 0; i < 4; i++ { 250 src.state[i] = binary.BigEndian.Uint64(data[i*8 : (i+1)*8]) 251 } 252 return nil 253 }