github.com/songzhibin97/gkit@v1.2.13/sys/fastrand/fastrand.go (about) 1 // Package fastrand is the fastest pseudorandom number generator in Go(multiple-cores). 2 package fastrand 3 4 import ( 5 "math/bits" 6 "unsafe" 7 8 "github.com/songzhibin97/gkit/internal/runtimex" 9 ) 10 11 // Uint32 returns a pseudo-random 32-bit value as a uint32. 12 var Uint32 = runtimex.Fastrand 13 14 // Uint64 returns a pseudo-random 64-bit value as a uint64. 15 func Uint64() uint64 { 16 return (uint64(runtimex.Fastrand()) << 32) | uint64(runtimex.Fastrand()) 17 } 18 19 // Int returns a non-negative pseudo-random int. 20 func Int() int { 21 // EQ 22 u := uint(Int63()) 23 return int(u << 1 >> 1) // clear sign bit if int == int32 24 } 25 26 // Int31 returns a non-negative pseudo-random 31-bit integer as an int32. 27 func Int31() int32 { return int32(Uint32() & (1<<31 - 1)) } 28 29 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64. 30 func Int63() int64 { 31 // EQ 32 return int64(Uint64() & (1<<63 - 1)) 33 } 34 35 // Int63n returns, as an int64, a non-negative pseudo-random number in [0,n). 36 // It panics if n <= 0. 37 func Int63n(n int64) int64 { 38 // EQ 39 if n <= 0 { 40 panic("invalid argument to Int63n") 41 } 42 if n&(n-1) == 0 { // n is power of two, can mask 43 return Int63() & (n - 1) 44 } 45 max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) 46 v := Int63() 47 for v > max { 48 v = Int63() 49 } 50 return v % n 51 } 52 53 // Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). 54 // It panics if n <= 0. 55 // For implementation details, see: 56 // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction 57 func Int31n(n int32) int32 { 58 // EQ 59 if n <= 0 { 60 panic("invalid argument to Int31n") 61 } 62 v := Uint32() 63 prod := uint64(v) * uint64(n) 64 low := uint32(prod) 65 if low < uint32(n) { 66 thresh := uint32(-n) % uint32(n) 67 for low < thresh { 68 v = Uint32() 69 prod = uint64(v) * uint64(n) 70 low = uint32(prod) 71 } 72 } 73 return int32(prod >> 32) 74 } 75 76 // Intn returns, as an int, a non-negative pseudo-random number in [0,n). 77 // It panics if n <= 0. 78 func Intn(n int) int { 79 // EQ 80 if n <= 0 { 81 panic("invalid argument to Intn") 82 } 83 if n <= 1<<31-1 { 84 return int(Int31n(int32(n))) 85 } 86 return int(Int63n(int64(n))) 87 } 88 89 func Float64() float64 { 90 // EQ 91 return float64(Int63n(1<<53)) / (1 << 53) 92 } 93 94 func Float32() float32 { 95 // EQ 96 return float32(Int31n(1<<24)) / (1 << 24) 97 } 98 99 // Uint32n returns a pseudo-random number in [0,n). 100 //go:nosplit 101 func Uint32n(n uint32) uint32 { 102 // This is similar to Uint32() % n, but faster. 103 // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 104 return uint32(uint64(Uint32()) * uint64(n) >> 32) 105 } 106 107 // Uint64n returns a pseudo-random number in [0,n). 108 func Uint64n(n uint64) uint64 { 109 return Uint64() % n 110 } 111 112 // wyrand: https://github.com/wangyi-fudan/wyhash 113 type wyrand uint64 114 115 func _wymix(a, b uint64) uint64 { 116 hi, lo := bits.Mul64(a, b) 117 return hi ^ lo 118 } 119 120 func (r *wyrand) Uint64() uint64 { 121 *r += wyrand(0xa0761d6478bd642f) 122 return _wymix(uint64(*r), uint64(*r^wyrand(0xe7037ed1a0b428db))) 123 } 124 125 func (r *wyrand) Uint64n(n uint64) uint64 { 126 return r.Uint64() % n 127 } 128 129 func (r *wyrand) Uint32() uint32 { 130 return uint32(Uint64()) 131 } 132 133 func (r *wyrand) Uint32n(n int) uint32 { 134 // This is similar to Uint32() % n, but faster. 135 // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 136 return uint32(uint64(r.Uint32()) * uint64(n) >> 32) 137 } 138 139 // Read generates len(p) random bytes and writes them into p. 140 // It always returns len(p) and a nil error. 141 // It is safe for concurrent use. 142 func Read(p []byte) (int, error) { 143 l := len(p) 144 if l == 0 { 145 return 0, nil 146 } 147 148 r := wyrand(Uint32()) 149 150 if l >= 8 { 151 var i int 152 uint64p := *(*[]uint64)(unsafe.Pointer(&p)) 153 for l >= 8 { 154 uint64p[i] = r.Uint64() 155 i++ 156 l -= 8 157 } 158 } 159 160 if l > 0 { 161 for l > 0 { 162 p[len(p)-l] = byte(r.Uint64() >> (l * 8)) 163 l-- 164 } 165 } 166 167 return len(p), nil 168 } 169 170 // Shuffle pseudo-randomizes the order of elements. 171 // n is the number of elements. Shuffle panics if n < 0. 172 // swap swaps the elements with indexes i and j. 173 func Shuffle(n int, swap func(i, j int)) { 174 if n < 0 { 175 panic("invalid argument to Shuffle") 176 } 177 // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 178 // Shuffle really ought not be called with n that doesn't fit in 32 bits. 179 // Not only will it take a very long time, but with 2³¹! possible permutations, 180 // there's no way that any PRNG can have a big enough internal state to 181 // generate even a minuscule percentage of the possible permutations. 182 // Nevertheless, the right API signature accepts an int n, so handle it as best we can. 183 i := n - 1 184 for ; i > 1<<31-1-1; i-- { 185 j := int(Int63n(int64(i + 1))) 186 swap(i, j) 187 } 188 for ; i > 0; i-- { 189 j := int(Int31n(int32(i + 1))) 190 swap(i, j) 191 } 192 } 193 194 // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers 195 // in the half-open interval [0,n). 196 func Perm(n int) []int { 197 m := make([]int, n) 198 for i := 1; i < n; i++ { 199 j := Intn(i + 1) 200 m[i] = m[j] 201 m[j] = i 202 } 203 return m 204 }