github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/perf/fastrand/rand.go (about) 1 // Copyright 2023 The Go 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 package fastrand 6 7 import "math/bits" 8 9 // A Source is a source of uniformly-distributed 10 // pseudo-random uint64 values in the range [0, 1<<64). 11 // 12 // A Source is not safe for concurrent use by multiple goroutines. 13 type Source interface { 14 Uint64() uint64 15 } 16 17 // A Rand is a source of random numbers. 18 type Rand struct { 19 src Source 20 } 21 22 // New returns a new Rand that uses random values from src 23 // to generate other random values. 24 func New(src Source) *Rand { 25 return &Rand{src: src} 26 } 27 28 // Uint64 returns a pseudo-random 64-bit value as a uint64. 29 func (r *Rand) Uint64() uint64 { return r.src.Uint64() } 30 31 // Int64 returns a non-negative pseudo-random 63-bit integer as an int64. 32 func (r *Rand) Int64() int64 { return int64(r.src.Uint64() &^ (1 << 63)) } 33 34 // Uint32 returns a pseudo-random 32-bit value as a uint32. 35 func (r *Rand) Uint32() uint32 { return uint32(r.src.Uint64() >> 32) } 36 37 // Int32 returns a non-negative pseudo-random 31-bit integer as an int32. 38 func (r *Rand) Int32() int32 { return int32(r.src.Uint64() >> 33) } 39 40 // Int returns a non-negative pseudo-random int. 41 func (r *Rand) Int() int { return int(uint(r.src.Uint64()) << 1 >> 1) } 42 43 // Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). 44 func (r *Rand) Float64() float64 { 45 // There are exactly 1<<53 float64s in [0,1). Use Intn(1<<53) / (1<<53). 46 return float64(r.Uint64()<<11>>11) / (1 << 53) 47 } 48 49 // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers 50 // in the half-open interval [0,n). 51 func (r *Rand) Perm(n int) []int { 52 p := make([]int, n) 53 for i := range p { 54 p[i] = i 55 } 56 r.Shuffle(len(p), func(i, j int) { p[i], p[j] = p[j], p[i] }) 57 return p 58 } 59 60 // Shuffle pseudo-randomizes the order of elements. 61 // n is the number of elements. Shuffle panics if n < 0. 62 // swap swaps the elements with indexes i and j. 63 func (r *Rand) Shuffle(n int, swap func(i, j int)) { 64 if n < 0 { 65 panic("invalid argument to Shuffle") 66 } 67 68 // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 69 // Shuffle really ought not be called with n that doesn't fit in 32 bits. 70 // Not only will it take a very long time, but with 2³¹! possible permutations, 71 // there's no way that any PRNG can have a big enough internal state to 72 // generate even a minuscule percentage of the possible permutations. 73 // Nevertheless, the right API signature accepts an int n, so handle it as best we can. 74 for i := n - 1; i > 0; i-- { 75 j := int(uint64n(r, uint64(i+1))) 76 swap(i, j) 77 } 78 } 79 80 // Uint64N returns, as an uint64, a non-negative pseudo-random number in the half-open interval [0,n). 81 // It panics if n == 0. 82 func (r *Rand) Uint64N(n uint64) uint64 { 83 if n == 0 { 84 panic("invalid argument to Uint64N") 85 } 86 return uint64n(r, n) 87 } 88 89 const is32bit = ^uint(0)>>32 == 0 90 91 // uint64n is the no-bounds-checks version of Uint64N. 92 func uint64n(s Source, n uint64) uint64 { 93 if is32bit && uint64(uint32(n)) == n { 94 return uint64(uint32n(s, uint32(n))) 95 } 96 if n&(n-1) == 0 { // n is power of two, can mask 97 return s.Uint64() & (n - 1) 98 } 99 100 // Suppose we have a uint64 x uniform in the range [0,2⁶⁴) 101 // and want to reduce it to the range [0,n) preserving exact uniformity. 102 // We can simulate a scaling arbitrary precision x * (n/2⁶⁴) by 103 // the high bits of a double-width multiply of x*n, meaning (x*n)/2⁶⁴. 104 // Since there are 2⁶⁴ possible inputs x and only n possible outputs, 105 // the output is necessarily biased if n does not divide 2⁶⁴. 106 // In general (x*n)/2⁶⁴ = k for x*n in [k*2⁶⁴,(k+1)*2⁶⁴). 107 // There are either floor(2⁶⁴/n) or ceil(2⁶⁴/n) possible products 108 // in that range, depending on k. 109 // But suppose we reject the sample and try again when 110 // x*n is in [k*2⁶⁴, k*2⁶⁴+(2⁶⁴%n)), meaning rejecting fewer than n possible 111 // outcomes out of the 2⁶⁴. 112 // Now there are exactly floor(2⁶⁴/n) possible ways to produce 113 // each output value k, so we've restored uniformity. 114 // To get valid uint64 math, 2⁶⁴ % n = (2⁶⁴ - n) % n = -n % n, 115 // so the direct implementation of this algorithm would be: 116 // 117 // hi, lo := bits.Mul64(r.Uint64(), n) 118 // thresh := -n % n 119 // for lo < thresh { 120 // hi, lo = bits.Mul64(r.Uint64(), n) 121 // } 122 // 123 // That still leaves an expensive 64-bit division that we would rather avoid. 124 // We know that thresh < n, and n is usually much less than 2⁶⁴, so we can 125 // avoid the last four lines unless lo < n. 126 // 127 // See also: 128 // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction 129 // https://lemire.me/blog/2016/06/30/fast-random-shuffling 130 hi, lo := bits.Mul64(s.Uint64(), n) 131 if lo < n { 132 thresh := -n % n 133 for lo < thresh { 134 hi, lo = bits.Mul64(s.Uint64(), n) 135 } 136 } 137 return hi 138 } 139 140 // uint32n is an identical computation to uint64n 141 // but optimized for 32-bit systems. 142 func uint32n(s Source, n uint32) uint32 { 143 if n&(n-1) == 0 { // n is power of two, can mask 144 return uint32(s.Uint64()) & (n - 1) 145 } 146 // On 64-bit systems we still use the uint64 code below because 147 // the probability of a random uint64 lo being < a uint32 n is near zero, 148 // meaning the unbiasing loop almost never runs. 149 // On 32-bit systems, here we need to implement that same logic in 32-bit math, 150 // both to preserve the exact output sequence observed on 64-bit machines 151 // and to preserve the optimization that the unbiasing loop almost never runs. 152 // 153 // We want to compute 154 // hi, lo := bits.Mul64(r.Uint64(), n) 155 // In terms of 32-bit halves, this is: 156 // x1:x0 := r.Uint64() 157 // 0:hi, lo1:lo0 := bits.Mul64(x1:x0, 0:n) 158 // Writing out the multiplication in terms of bits.Mul32 allows 159 // using direct hardware instructions and avoiding 160 // the computations involving these zeros. 161 x := s.Uint64() 162 lo1a, lo0 := bits.Mul32(uint32(x), n) 163 hi, lo1b := bits.Mul32(uint32(x>>32), n) 164 lo1, c := bits.Add32(lo1a, lo1b, 0) 165 hi += c 166 if lo1 == 0 && lo0 < n { 167 n64 := uint64(n) 168 thresh := uint32(-n64 % n64) 169 for lo1 == 0 && lo0 < thresh { 170 x := s.Uint64() 171 lo1a, lo0 = bits.Mul32(uint32(x), n) 172 hi, lo1b = bits.Mul32(uint32(x>>32), n) 173 lo1, c = bits.Add32(lo1a, lo1b, 0) 174 hi += c 175 } 176 } 177 return hi 178 }