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  }