github.com/songzhibin97/gkit@v1.2.13/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/gkit/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  //go:nosplit
   101  func Uint32n(n uint32) uint32 {
   102  	// This is similar to Uint32() % n, but faster.
   103  	// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
   104  	return uint32(uint64(Uint32()) * uint64(n) >> 32)
   105  }
   106  
   107  // Uint64n returns a pseudo-random number in [0,n).
   108  func Uint64n(n uint64) uint64 {
   109  	return Uint64() % n
   110  }
   111  
   112  // wyrand: https://github.com/wangyi-fudan/wyhash
   113  type wyrand uint64
   114  
   115  func _wymix(a, b uint64) uint64 {
   116  	hi, lo := bits.Mul64(a, b)
   117  	return hi ^ lo
   118  }
   119  
   120  func (r *wyrand) Uint64() uint64 {
   121  	*r += wyrand(0xa0761d6478bd642f)
   122  	return _wymix(uint64(*r), uint64(*r^wyrand(0xe7037ed1a0b428db)))
   123  }
   124  
   125  func (r *wyrand) Uint64n(n uint64) uint64 {
   126  	return r.Uint64() % n
   127  }
   128  
   129  func (r *wyrand) Uint32() uint32 {
   130  	return uint32(Uint64())
   131  }
   132  
   133  func (r *wyrand) Uint32n(n int) uint32 {
   134  	// This is similar to Uint32() % n, but faster.
   135  	// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
   136  	return uint32(uint64(r.Uint32()) * uint64(n) >> 32)
   137  }
   138  
   139  // Read generates len(p) random bytes and writes them into p.
   140  // It always returns len(p) and a nil error.
   141  // It is safe for concurrent use.
   142  func Read(p []byte) (int, error) {
   143  	l := len(p)
   144  	if l == 0 {
   145  		return 0, nil
   146  	}
   147  
   148  	r := wyrand(Uint32())
   149  
   150  	if l >= 8 {
   151  		var i int
   152  		uint64p := *(*[]uint64)(unsafe.Pointer(&p))
   153  		for l >= 8 {
   154  			uint64p[i] = r.Uint64()
   155  			i++
   156  			l -= 8
   157  		}
   158  	}
   159  
   160  	if l > 0 {
   161  		for l > 0 {
   162  			p[len(p)-l] = byte(r.Uint64() >> (l * 8))
   163  			l--
   164  		}
   165  	}
   166  
   167  	return len(p), nil
   168  }
   169  
   170  // Shuffle pseudo-randomizes the order of elements.
   171  // n is the number of elements. Shuffle panics if n < 0.
   172  // swap swaps the elements with indexes i and j.
   173  func Shuffle(n int, swap func(i, j int)) {
   174  	if n < 0 {
   175  		panic("invalid argument to Shuffle")
   176  	}
   177  	// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
   178  	// Shuffle really ought not be called with n that doesn't fit in 32 bits.
   179  	// Not only will it take a very long time, but with 2³¹! possible permutations,
   180  	// there's no way that any PRNG can have a big enough internal state to
   181  	// generate even a minuscule percentage of the possible permutations.
   182  	// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
   183  	i := n - 1
   184  	for ; i > 1<<31-1-1; i-- {
   185  		j := int(Int63n(int64(i + 1)))
   186  		swap(i, j)
   187  	}
   188  	for ; i > 0; i-- {
   189  		j := int(Int31n(int32(i + 1)))
   190  		swap(i, j)
   191  	}
   192  }
   193  
   194  // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
   195  // in the half-open interval [0,n).
   196  func Perm(n int) []int {
   197  	m := make([]int, n)
   198  	for i := 1; i < n; i++ {
   199  		j := Intn(i + 1)
   200  		m[i] = m[j]
   201  		m[j] = i
   202  	}
   203  	return m
   204  }