github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/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/go-baseutils/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 // 101 //go:nosplit 102 func Uint32n(n uint32) uint32 { 103 // This is similar to Uint32() % n, but faster. 104 // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 105 return uint32(uint64(Uint32()) * uint64(n) >> 32) 106 } 107 108 // Uint64n returns a pseudo-random number in [0,n). 109 func Uint64n(n uint64) uint64 { 110 return Uint64() % n 111 } 112 113 // wyrand: https://github.com/wangyi-fudan/wyhash 114 type wyrand uint64 115 116 func _wymix(a, b uint64) uint64 { 117 hi, lo := bits.Mul64(a, b) 118 return hi ^ lo 119 } 120 121 func (r *wyrand) Uint64() uint64 { 122 *r += wyrand(0xa0761d6478bd642f) 123 return _wymix(uint64(*r), uint64(*r^wyrand(0xe7037ed1a0b428db))) 124 } 125 126 func (r *wyrand) Uint64n(n uint64) uint64 { 127 return r.Uint64() % n 128 } 129 130 func (r *wyrand) Uint32() uint32 { 131 return uint32(Uint64()) 132 } 133 134 func (r *wyrand) Uint32n(n int) uint32 { 135 // This is similar to Uint32() % n, but faster. 136 // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 137 return uint32(uint64(r.Uint32()) * uint64(n) >> 32) 138 } 139 140 // Read generates len(p) random bytes and writes them into p. 141 // It always returns len(p) and a nil error. 142 // It is safe for concurrent use. 143 func Read(p []byte) (int, error) { 144 l := len(p) 145 if l == 0 { 146 return 0, nil 147 } 148 149 r := wyrand(Uint32()) 150 151 if l >= 8 { 152 var i int 153 uint64p := *(*[]uint64)(unsafe.Pointer(&p)) 154 for l >= 8 { 155 uint64p[i] = r.Uint64() 156 i++ 157 l -= 8 158 } 159 } 160 161 if l > 0 { 162 for l > 0 { 163 p[len(p)-l] = byte(r.Uint64() >> (l * 8)) 164 l-- 165 } 166 } 167 168 return len(p), nil 169 } 170 171 // Shuffle pseudo-randomizes the order of elements. 172 // n is the number of elements. Shuffle panics if n < 0. 173 // swap swaps the elements with indexes i and j. 174 func Shuffle(n int, swap func(i, j int)) { 175 if n < 0 { 176 panic("invalid argument to Shuffle") 177 } 178 // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 179 // Shuffle really ought not be called with n that doesn't fit in 32 bits. 180 // Not only will it take a very long time, but with 2³¹! possible permutations, 181 // there's no way that any PRNG can have a big enough internal state to 182 // generate even a minuscule percentage of the possible permutations. 183 // Nevertheless, the right API signature accepts an int n, so handle it as best we can. 184 i := n - 1 185 for ; i > 1<<31-1-1; i-- { 186 j := int(Int63n(int64(i + 1))) 187 swap(i, j) 188 } 189 for ; i > 0; i-- { 190 j := int(Int31n(int32(i + 1))) 191 swap(i, j) 192 } 193 } 194 195 // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers 196 // in the half-open interval [0,n). 197 func Perm(n int) []int { 198 m := make([]int, n) 199 for i := 1; i < n; i++ { 200 j := Intn(i + 1) 201 m[i] = m[j] 202 m[j] = i 203 } 204 return m 205 }