gonum.org/v1/gonum@v0.14.0/internal/testrand/extreme.go (about) 1 // Copyright ©2020 The Gonum 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 testrand 6 7 import ( 8 "math" 9 10 "golang.org/x/exp/rand" 11 ) 12 13 // extreme is a pseudo-random number generator that has high probability of returning extreme values. 14 type extreme struct { 15 probability float64 16 nanProbability float64 17 18 rnd Rand 19 } 20 21 // newExtreme creates a new extreme pseudo-random generator. 22 // p is the probability of returning an extreme value. 23 // nan is the probability of returning a NaN. 24 func newExtreme(p, nan float64, rnd Rand) *extreme { 25 return &extreme{p, nan, rnd} 26 } 27 28 // Perm returns a permutation of integers [0, n). 29 func (e *extreme) Perm(n int) []int { return e.rnd.Perm(n) } 30 31 // Read generates len(p) pseudo-random bytes. 32 func (e *extreme) Read(p []byte) (n int, err error) { return e.rnd.Read(p) } 33 34 // Seed reseeds the pseudo-random generator. 35 func (e *extreme) Seed(seed uint64) { e.rnd.Seed(seed) } 36 37 // Shuffle shuffles n items using the swap callback. 38 func (e *extreme) Shuffle(n int, swap func(i, j int)) { e.rnd.Shuffle(n, swap) } 39 40 // p returns true when the generator should output an extreme value. 41 func (e *extreme) p() bool { 42 if e.probability <= 0 { 43 return false 44 } 45 return e.rnd.Float64() < e.probability 46 } 47 48 // nan returns true when the generator should output nan. 49 func (e *extreme) nan() bool { 50 if e.nanProbability <= 0 { 51 return false 52 } 53 return e.rnd.Float64() < e.nanProbability 54 } 55 56 // ExpFloat64 returns an exponentialy distributed pseudo-random float64 in range (0, math.MaxFloat64]. 57 func (e *extreme) ExpFloat64() float64 { 58 switch { 59 case e.p(): 60 return extremeFloat64Exp[e.rnd.Intn(len(extremeFloat64Exp))] 61 case e.nan(): 62 return math.NaN() 63 } 64 65 return e.rnd.ExpFloat64() 66 } 67 68 // Float32 returns a pseudo-random float32 in range [0.0, 1.0). 69 func (e *extreme) Float32() float32 { 70 switch { 71 case e.p(): 72 return extremeFloat32Unit[e.rnd.Intn(len(extremeFloat32Unit))] 73 case e.nan(): 74 return float32(math.NaN()) 75 } 76 77 return e.rnd.Float32() 78 } 79 80 // Float64 returns a pseudo-random float64 in range [0.0, 1.0). 81 func (e *extreme) Float64() float64 { 82 switch { 83 case e.p(): 84 return extremeFloat64Unit[e.rnd.Intn(len(extremeFloat64Unit))] 85 case e.nan(): 86 return math.NaN() 87 } 88 89 return e.rnd.Float64() 90 } 91 92 // Int returns a non-negative pseudo-random int. 93 func (e *extreme) Int() int { 94 if e.p() { 95 return extremeInt[e.rnd.Intn(len(extremeInt))] 96 } 97 return e.rnd.Int() 98 } 99 100 // Int31 returns a non-negative pseudo-random int32. 101 func (e *extreme) Int31() int32 { 102 if e.p() { 103 return extremeInt31[e.rnd.Intn(len(extremeInt31))] 104 } 105 return e.rnd.Int31() 106 } 107 108 // Int31n returns a non-negative pseudo-random int32 from range [0, n). 109 func (e *extreme) Int31n(n int32) int32 { 110 if e.p() { 111 switch rand.Intn(4) { 112 case 0: 113 return 0 114 case 1: 115 return 1 116 case 2: 117 return n / 2 118 case 3: 119 return n - 1 120 } 121 } 122 return e.rnd.Int31n(n) 123 } 124 125 // Int63 returns a non-negative pseudo-random int64. 126 func (e *extreme) Int63() int64 { 127 if e.p() { 128 return extremeInt63[e.rnd.Intn(len(extremeInt63))] 129 } 130 return e.rnd.Int63() 131 } 132 133 // Int63n returns a non-negative pseudo-random int from range [0, n). 134 func (e *extreme) Int63n(n int64) int64 { 135 if e.p() { 136 switch rand.Intn(4) { 137 case 0: 138 return 0 139 case 1: 140 return 1 141 case 2: 142 return n / 2 143 case 3: 144 return n - 1 145 } 146 } 147 return e.rnd.Int63n(n) 148 } 149 150 // Int returns a non-negative pseudo-random int from range [0, n). 151 func (e *extreme) Intn(n int) int { 152 if e.p() { 153 switch rand.Intn(4) { 154 case 0: 155 return 0 156 case 1: 157 return 1 158 case 2: 159 return n / 2 160 case 3: 161 return n - 1 162 } 163 } 164 return e.rnd.Intn(n) 165 } 166 167 // NormFloat64 returns a normally distributed pseudo-random float64 in range [-math.MaxFloat64, math.MaxFloat64]. 168 func (e *extreme) NormFloat64() float64 { 169 switch { 170 case e.p(): 171 return extremeFloat64Norm[e.rnd.Intn(len(extremeFloat64Norm))] 172 case e.nan(): 173 return math.NaN() 174 } 175 176 return e.rnd.NormFloat64() 177 } 178 179 // Uint32 returns a pseudo-random uint32. 180 func (e *extreme) Uint32() uint32 { 181 if e.p() { 182 return extremeUint32[e.rnd.Intn(len(extremeUint32))] 183 } 184 return e.rnd.Uint32() 185 } 186 187 // Uint32 returns a pseudo-random uint64. 188 func (e *extreme) Uint64() uint64 { 189 if e.p() { 190 return extremeUint64[e.rnd.Intn(len(extremeUint64))] 191 } 192 return e.rnd.Uint64() 193 } 194 195 // Uint64n returns a pseudo-random uint64 from range [0, n). 196 func (e *extreme) Uint64n(n uint64) uint64 { 197 if e.p() { 198 switch rand.Intn(4) { 199 case 0: 200 return 0 201 case 1: 202 return 1 203 case 2: 204 return n / 2 205 case 3: 206 return n - 1 207 } 208 } 209 return e.rnd.Uint64n(n) 210 }