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  }