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