pgregory.net/rand@v1.0.3-0.20230808192358-a0b8ce02f4da/global.go (about) 1 // Copyright 2022 Gregory Petrosyan <gregory.petrosyan@gmail.com> 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at https://mozilla.org/MPL/2.0/. 6 7 package rand 8 9 import ( 10 "encoding/binary" 11 "math" 12 "math/bits" 13 ) 14 15 // Float32 returns, as a float32, a uniformly distributed pseudo-random number in the half-open interval [0.0, 1.0). 16 func Float32() float32 { 17 return float32(rand64()&int24Mask) * f24Mul 18 } 19 20 // Float64 returns, as a float64, a uniformly distributed pseudo-random number in the half-open interval [0.0, 1.0). 21 func Float64() float64 { 22 return float64(rand64()&int53Mask) * f53Mul 23 } 24 25 // Int returns a uniformly distributed non-negative pseudo-random int. 26 func Int() int { 27 return int(rand64() & intMask) 28 } 29 30 // Int31 returns a uniformly distributed non-negative pseudo-random 31-bit integer as an int32. 31 func Int31() int32 { 32 return int32(rand64() & int31Mask) 33 } 34 35 // Int31n returns, as an int32, a uniformly distributed non-negative pseudo-random number 36 // in the half-open interval [0, n). It panics if n <= 0. 37 func Int31n(n int32) int32 { 38 if n <= 0 { 39 panic("invalid argument to Int31n") 40 } 41 return int32(Uint32n(uint32(n))) 42 } 43 44 // Int63 returns a uniformly distributed non-negative pseudo-random 63-bit integer as an int64. 45 func Int63() int64 { 46 return int64(rand64() & int63Mask) 47 } 48 49 // Int63n returns, as an int64, a uniformly distributed non-negative pseudo-random number 50 // in the half-open interval [0, n). It panics if n <= 0. 51 func Int63n(n int64) int64 { 52 if n <= 0 { 53 panic("invalid argument to Int63n") 54 } 55 return int64(Uint64n(uint64(n))) 56 } 57 58 // Intn returns, as an int, a uniformly distributed non-negative pseudo-random number 59 // in the half-open interval [0, n). It panics if n <= 0. 60 func Intn(n int) int { 61 if n <= 0 { 62 panic("invalid argument to Intn") 63 } 64 if math.MaxInt == math.MaxInt32 { 65 return int(Uint32n(uint32(n))) 66 } else { 67 return int(Uint64n(uint64(n))) 68 } 69 } 70 71 // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers in the half-open interval [0, n). 72 func Perm(n int) []int { 73 p := make([]int, n) 74 perm(p) 75 return p 76 } 77 78 func perm(p []int) { 79 // see Rand.perm 80 n := len(p) 81 b := n 82 if b > math.MaxInt32 { 83 b = math.MaxInt32 84 } 85 i := 1 86 for ; i < b; i++ { 87 j := Uint32n(uint32(i) + 1) 88 p[i] = p[j] 89 p[j] = i 90 } 91 for ; i < n; i++ { 92 j := Uint64n(uint64(i) + 1) 93 p[i] = p[j] 94 p[j] = i 95 } 96 } 97 98 // Read generates len(p) pseudo-random bytes and writes them into p. It always returns len(p) and a nil error. 99 func Read(p []byte) (n int, err error) { 100 // see Rand.Read 101 for ; n+8 <= len(p); n += 8 { 102 binary.LittleEndian.PutUint64(p[n:n+8], rand64()) 103 } 104 if n < len(p) { 105 val := rand64() 106 for ; n < len(p); n++ { 107 p[n] = byte(val) 108 val >>= 8 109 } 110 } 111 return 112 } 113 114 // Shuffle pseudo-randomizes the order of elements. n is the number of elements. Shuffle panics if n < 0. 115 // swap swaps the elements with indexes i and j. 116 // 117 // For shuffling elements of a slice, prefer the top-level [ShuffleSlice] function. 118 func Shuffle(n int, swap func(i, j int)) { 119 // see Rand.Shuffle 120 if n < 0 { 121 panic("invalid argument to Shuffle") 122 } 123 i := n - 1 124 for ; i > math.MaxInt32-1; i-- { 125 j := int(Uint64n(uint64(i) + 1)) 126 swap(i, j) 127 } 128 for ; i > 0; i-- { 129 j := int(Uint32n(uint32(i) + 1)) 130 swap(i, j) 131 } 132 } 133 134 // Uint32 returns a uniformly distributed pseudo-random 32-bit value as an uint32. 135 func Uint32() uint32 { 136 return uint32(rand64()) 137 } 138 139 // Uint32n returns, as an uint32, a uniformly distributed pseudo-random number in [0, n). Uint32n(0) returns 0. 140 func Uint32n(n uint32) uint32 { 141 // see Rand.Uint32n 142 res, _ := bits.Mul64(uint64(n), rand64()) 143 return uint32(res) 144 } 145 146 // Uint64 returns a uniformly distributed pseudo-random 64-bit value as an uint64. 147 func Uint64() uint64 { 148 return rand64() 149 } 150 151 // Uint64n returns, as an uint64, a uniformly distributed pseudo-random number in [0, n). Uint64n(0) returns 0. 152 func Uint64n(n uint64) uint64 { 153 // see Rand.Uint64n 154 res, frac := bits.Mul64(n, rand64()) 155 if n <= math.MaxUint32 { 156 return res 157 } 158 hi, _ := bits.Mul64(n, rand64()) 159 _, carry := bits.Add64(frac, hi, 0) 160 return res + carry 161 }