github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/sys/fastrand/fastrand.go (about)

     1  // Package fastrand is the fastest pseudorandom number generator in Go(multiple-cores).
     2  package fastrand
     3  
     4  import (
     5  	"math/bits"
     6  	"unsafe"
     7  
     8  	"github.com/songzhibin97/go-baseutils/internal/runtimex"
     9  )
    10  
    11  // Uint32 returns a pseudo-random 32-bit value as a uint32.
    12  var Uint32 = runtimex.Fastrand
    13  
    14  // Uint64 returns a pseudo-random 64-bit value as a uint64.
    15  func Uint64() uint64 {
    16  	return (uint64(runtimex.Fastrand()) << 32) | uint64(runtimex.Fastrand())
    17  }
    18  
    19  // Int returns a non-negative pseudo-random int.
    20  func Int() int {
    21  	// EQ
    22  	u := uint(Int63())
    23  	return int(u << 1 >> 1) // clear sign bit if int == int32
    24  }
    25  
    26  // Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
    27  func Int31() int32 { return int32(Uint32() & (1<<31 - 1)) }
    28  
    29  // Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
    30  func Int63() int64 {
    31  	// EQ
    32  	return int64(Uint64() & (1<<63 - 1))
    33  }
    34  
    35  // Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
    36  // It panics if n <= 0.
    37  func Int63n(n int64) int64 {
    38  	// EQ
    39  	if n <= 0 {
    40  		panic("invalid argument to Int63n")
    41  	}
    42  	if n&(n-1) == 0 { // n is power of two, can mask
    43  		return Int63() & (n - 1)
    44  	}
    45  	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
    46  	v := Int63()
    47  	for v > max {
    48  		v = Int63()
    49  	}
    50  	return v % n
    51  }
    52  
    53  // Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
    54  // It panics if n <= 0.
    55  // For implementation details, see:
    56  // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction
    57  func Int31n(n int32) int32 {
    58  	// EQ
    59  	if n <= 0 {
    60  		panic("invalid argument to Int31n")
    61  	}
    62  	v := Uint32()
    63  	prod := uint64(v) * uint64(n)
    64  	low := uint32(prod)
    65  	if low < uint32(n) {
    66  		thresh := uint32(-n) % uint32(n)
    67  		for low < thresh {
    68  			v = Uint32()
    69  			prod = uint64(v) * uint64(n)
    70  			low = uint32(prod)
    71  		}
    72  	}
    73  	return int32(prod >> 32)
    74  }
    75  
    76  // Intn returns, as an int, a non-negative pseudo-random number in [0,n).
    77  // It panics if n <= 0.
    78  func Intn(n int) int {
    79  	// EQ
    80  	if n <= 0 {
    81  		panic("invalid argument to Intn")
    82  	}
    83  	if n <= 1<<31-1 {
    84  		return int(Int31n(int32(n)))
    85  	}
    86  	return int(Int63n(int64(n)))
    87  }
    88  
    89  func Float64() float64 {
    90  	// EQ
    91  	return float64(Int63n(1<<53)) / (1 << 53)
    92  }
    93  
    94  func Float32() float32 {
    95  	// EQ
    96  	return float32(Int31n(1<<24)) / (1 << 24)
    97  }
    98  
    99  // Uint32n returns a pseudo-random number in [0,n).
   100  //
   101  //go:nosplit
   102  func Uint32n(n uint32) uint32 {
   103  	// This is similar to Uint32() % n, but faster.
   104  	// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
   105  	return uint32(uint64(Uint32()) * uint64(n) >> 32)
   106  }
   107  
   108  // Uint64n returns a pseudo-random number in [0,n).
   109  func Uint64n(n uint64) uint64 {
   110  	return Uint64() % n
   111  }
   112  
   113  // wyrand: https://github.com/wangyi-fudan/wyhash
   114  type wyrand uint64
   115  
   116  func _wymix(a, b uint64) uint64 {
   117  	hi, lo := bits.Mul64(a, b)
   118  	return hi ^ lo
   119  }
   120  
   121  func (r *wyrand) Uint64() uint64 {
   122  	*r += wyrand(0xa0761d6478bd642f)
   123  	return _wymix(uint64(*r), uint64(*r^wyrand(0xe7037ed1a0b428db)))
   124  }
   125  
   126  func (r *wyrand) Uint64n(n uint64) uint64 {
   127  	return r.Uint64() % n
   128  }
   129  
   130  func (r *wyrand) Uint32() uint32 {
   131  	return uint32(Uint64())
   132  }
   133  
   134  func (r *wyrand) Uint32n(n int) uint32 {
   135  	// This is similar to Uint32() % n, but faster.
   136  	// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
   137  	return uint32(uint64(r.Uint32()) * uint64(n) >> 32)
   138  }
   139  
   140  // Read generates len(p) random bytes and writes them into p.
   141  // It always returns len(p) and a nil error.
   142  // It is safe for concurrent use.
   143  func Read(p []byte) (int, error) {
   144  	l := len(p)
   145  	if l == 0 {
   146  		return 0, nil
   147  	}
   148  
   149  	r := wyrand(Uint32())
   150  
   151  	if l >= 8 {
   152  		var i int
   153  		uint64p := *(*[]uint64)(unsafe.Pointer(&p))
   154  		for l >= 8 {
   155  			uint64p[i] = r.Uint64()
   156  			i++
   157  			l -= 8
   158  		}
   159  	}
   160  
   161  	if l > 0 {
   162  		for l > 0 {
   163  			p[len(p)-l] = byte(r.Uint64() >> (l * 8))
   164  			l--
   165  		}
   166  	}
   167  
   168  	return len(p), nil
   169  }
   170  
   171  // Shuffle pseudo-randomizes the order of elements.
   172  // n is the number of elements. Shuffle panics if n < 0.
   173  // swap swaps the elements with indexes i and j.
   174  func Shuffle(n int, swap func(i, j int)) {
   175  	if n < 0 {
   176  		panic("invalid argument to Shuffle")
   177  	}
   178  	// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
   179  	// Shuffle really ought not be called with n that doesn't fit in 32 bits.
   180  	// Not only will it take a very long time, but with 2³¹! possible permutations,
   181  	// there's no way that any PRNG can have a big enough internal state to
   182  	// generate even a minuscule percentage of the possible permutations.
   183  	// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
   184  	i := n - 1
   185  	for ; i > 1<<31-1-1; i-- {
   186  		j := int(Int63n(int64(i + 1)))
   187  		swap(i, j)
   188  	}
   189  	for ; i > 0; i-- {
   190  		j := int(Int31n(int32(i + 1)))
   191  		swap(i, j)
   192  	}
   193  }
   194  
   195  // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
   196  // in the half-open interval [0,n).
   197  func Perm(n int) []int {
   198  	m := make([]int, n)
   199  	for i := 1; i < n; i++ {
   200  		j := Intn(i + 1)
   201  		m[i] = m[j]
   202  		m[j] = i
   203  	}
   204  	return m
   205  }