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