bursavich.dev/fastrand@v0.2.1/fastrand.go (about)

     1  // SPDX-License-Identifier: MIT
     2  //
     3  // Copyright 2023 Andrew Bursavich. All rights reserved.
     4  // Use of this source code is governed by The MIT License
     5  // which can be found in the LICENSE file.
     6  
     7  // Package fastrand provides quickly generated pseudo-random numbers
     8  // with no repeatability guarantees on the stream of values.
     9  package fastrand
    10  
    11  import (
    12  	"io"
    13  
    14  	"golang.org/x/exp/constraints"
    15  )
    16  
    17  const (
    18  	maxUint32 = (1 << 32) - 1
    19  	maxUint64 = (1 << 64) - 1
    20  	maxInt32  = maxUint32 >> 1
    21  	maxInt64  = maxUint64 >> 1
    22  )
    23  
    24  // Float32 returns a pseudo-random float32 in the half-open interval [0,n).
    25  func Float32() float32 {
    26  	const (
    27  		mask = 1<<24 - 1
    28  		mult = 0x1.0p-24
    29  	)
    30  	return float32(u32()&mask) * mult
    31  }
    32  
    33  // Float64 returns a pseudo-random float64 in the half-open interval [0,n).
    34  func Float64() float64 {
    35  	const (
    36  		mask = 1<<53 - 1
    37  		mult = 0x1.0p-53
    38  	)
    39  	return float64(u64()&mask) * mult
    40  }
    41  
    42  // Int31 returns a non-negative pseudo-random int32.
    43  func Int31() int32 {
    44  	return int32(u32() >> 1)
    45  }
    46  
    47  // Int31n returns a non-negative pseudo-random int32 in the half-open interval [0,n).
    48  // It panics if n <= 0.
    49  func Int31n(n int32) int32 {
    50  	if n <= 0 {
    51  		panic("fastrand.Int31n: invalid argument")
    52  	}
    53  	if n&(n-1) == 0 { // n is power of two, can mask
    54  		return Int31() & (n - 1)
    55  	}
    56  	max := maxInt32 - maxInt32%n
    57  	v := Int31()
    58  	for v >= max {
    59  		v = Int31()
    60  	}
    61  	return v % n
    62  }
    63  
    64  // Int63 returns a non-negative pseudo-random int64.
    65  func Int63() int64 {
    66  	return int64(u64() >> 1)
    67  }
    68  
    69  // Int63n returns a non-negative pseudo-random int64 in the half-open interval [0,n).
    70  // It panics if n <= 0.
    71  func Int63n(n int64) int64 {
    72  	if n <= 0 {
    73  		panic("fastrand.Int63n: invalid argument")
    74  	}
    75  	if n&(n-1) == 0 { // n is power of two, can mask
    76  		return Int63() & (n - 1)
    77  	}
    78  	max := maxInt64 - maxInt64%n
    79  	v := Int63()
    80  	for v >= max {
    81  		v = Int63()
    82  	}
    83  	return v % n
    84  }
    85  
    86  // Uint32 returns a pseudo-random uint32.
    87  func Uint32() uint32 {
    88  	return u32()
    89  }
    90  
    91  // Uint32n returns a pseudo-random uint32 in the half-open interval [0,n).
    92  func Uint64nUint32n(n uint32) uint32 {
    93  	if n&(n-1) == 0 { // n is power of two, can mask
    94  		return u32() & (n - 1)
    95  	}
    96  	max := maxUint32 - maxUint32%uint32(n)
    97  	v := u32()
    98  	for v >= max {
    99  		v = u32()
   100  	}
   101  	return v % n
   102  }
   103  
   104  // Uint64 returns a pseudo-random uint64.
   105  func Uint64() uint64 {
   106  	return u64()
   107  }
   108  
   109  // Uint64n returns a pseudo-random uint64 in the half-open interval [0,n).
   110  func Uint64n(n uint64) uint64 {
   111  	if n&(n-1) == 0 { // n is power of two, can mask
   112  		return u64() & (n - 1)
   113  	}
   114  	max := maxUint64 - maxUint64%uint64(n)
   115  	v := u64()
   116  	for v >= max {
   117  		v = u64()
   118  	}
   119  	return v % n
   120  }
   121  
   122  // A Real is a real number.
   123  type Real interface {
   124  	constraints.Signed | constraints.Unsigned
   125  }
   126  
   127  // Jitter returns a pseudo-random value in the interval [v - factor*v, v + factor*v].
   128  func Jitter[T Real](v T, factor float64) T {
   129  	r := Float64()
   130  	// r = [0, 1)
   131  	// 2*r = [0, 2)
   132  	// 2*r - 1 = [-1, 1)
   133  	// j*(2*r - 1) = [-j, j)
   134  	// 1 + j*(2*r - 1) = [1 - j, 1 + j)
   135  	// b*(1 + j*(2*r - 1)) = [b - j*b, b + j*b)
   136  	return T(float64(v) * (1 + (factor * (2*r - 1))))
   137  }
   138  
   139  // Shuffle pseudo-randomizes the order of elements in s.
   140  func Shuffle[E any](s []E) {
   141  	// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
   142  	i := len(s) - 1
   143  	// Shuffle really ought not be called with slice indices that requires more than 31 bits.
   144  	// Nevertheless, handle it as best we can.
   145  	for ; i >= maxInt32-1; i-- {
   146  		j := Int63n(int64(i + 1))
   147  		s[i], s[j] = s[j], s[i]
   148  	}
   149  	// Switch to 31-bit indices.
   150  	for ; i > 0; i-- {
   151  		j := Int31n(int32(i + 1))
   152  		s[i], s[j] = s[j], s[i]
   153  	}
   154  }
   155  
   156  var ioReader io.Reader = &reader{}
   157  
   158  // Reader returns an io.Reader that fills the read buffer with
   159  // pseudo-random bytes and never returns an error.
   160  func Reader() io.Reader {
   161  	return ioReader
   162  }
   163  
   164  type reader struct{}
   165  
   166  func (*reader) Read(p []byte) (int, error) {
   167  	Fill(p)
   168  	return len(p), nil
   169  }
   170  
   171  // Fill fills b with pseudo-random bytes.
   172  func Fill(p []byte) {
   173  	for len(p) >= 8 {
   174  		putU64(p, u64())
   175  		p = p[8:]
   176  	}
   177  	switch {
   178  	case len(p) > 4:
   179  		fill(p, u64())
   180  	case len(p) > 0:
   181  		fill(p, u32())
   182  	}
   183  }
   184  
   185  func fill[T interface{ uint32 | uint64 }](p []byte, v T) {
   186  	for i := range p {
   187  		p[i] = byte(v >> (i * 8))
   188  	}
   189  }