117 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package rand // import "go.unistack.org/micro/v3/util/rand"
 | |
| 
 | |
| import (
 | |
| 	crand "crypto/rand"
 | |
| 	"encoding/binary"
 | |
| )
 | |
| 
 | |
| // Rand is a wrapper around crypto/rand that adds some convenience functions known from math/rand
 | |
| type Rand struct {
 | |
| 	buf [8]byte
 | |
| }
 | |
| 
 | |
| // Int31 function implementation
 | |
| func (r *Rand) Int31() int32 {
 | |
| 	_, _ = crand.Read(r.buf[:4])
 | |
| 	return int32(binary.BigEndian.Uint32(r.buf[:4]) & ^uint32(1<<31))
 | |
| }
 | |
| 
 | |
| // Int function implementation
 | |
| func (r *Rand) Int() int {
 | |
| 	u := uint(r.Int63())
 | |
| 	return int(u << 1 >> 1) // clear sign bit if int == int32
 | |
| }
 | |
| 
 | |
| // Float64 function implementation
 | |
| func (r *Rand) Float64() float64 {
 | |
| again:
 | |
| 	f := float64(r.Int63()) / (1 << 63)
 | |
| 	if f == 1 {
 | |
| 		goto again // resample; this branch is taken O(never)
 | |
| 	}
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| // Float32 function implementation
 | |
| func (r *Rand) Float32() float32 {
 | |
| again:
 | |
| 	f := float32(r.Float64())
 | |
| 	if f == 1 {
 | |
| 		goto again // resample; this branch is taken O(very rarely)
 | |
| 	}
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| // Uint32 function implementation
 | |
| func (r *Rand) Uint32() uint32 {
 | |
| 	return uint32(r.Int63() >> 31)
 | |
| }
 | |
| 
 | |
| // Uint64 function implementation
 | |
| func (r *Rand) Uint64() uint64 {
 | |
| 	return uint64(r.Int63())>>31 | uint64(r.Int63())<<32
 | |
| }
 | |
| 
 | |
| // Intn function implementation
 | |
| func (r *Rand) Intn(n int) int {
 | |
| 	if n <= 1<<31-1 {
 | |
| 		return int(r.Int31n(int32(n)))
 | |
| 	}
 | |
| 	return int(r.Int63n(int64(n)))
 | |
| }
 | |
| 
 | |
| // Int63 function implementation
 | |
| func (r *Rand) Int63() int64 {
 | |
| 	_, _ = crand.Read(r.buf[:])
 | |
| 	return int64(binary.BigEndian.Uint64(r.buf[:]) & ^uint64(1<<63))
 | |
| }
 | |
| 
 | |
| // Int31n function implementation copied from the standard library math/rand implementation of Int31n
 | |
| func (r *Rand) Int31n(n int32) int32 {
 | |
| 	if n&(n-1) == 0 { // n is power of two, can mask
 | |
| 		return r.Int31() & (n - 1)
 | |
| 	}
 | |
| 	max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
 | |
| 	v := r.Int31()
 | |
| 	for v > max {
 | |
| 		v = r.Int31()
 | |
| 	}
 | |
| 	return v % n
 | |
| }
 | |
| 
 | |
| // Int63n function implementation copied from the standard library math/rand implementation of Int63n
 | |
| func (r *Rand) Int63n(n int64) int64 {
 | |
| 	if n&(n-1) == 0 { // n is power of two, can mask
 | |
| 		return r.Int63() & (n - 1)
 | |
| 	}
 | |
| 	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
 | |
| 	v := r.Int63()
 | |
| 	for v > max {
 | |
| 		v = r.Int63()
 | |
| 	}
 | |
| 	return v % n
 | |
| }
 | |
| 
 | |
| // Shuffle function implementation copied from the standard library math/rand implementation of Shuffle
 | |
| func (r *Rand) Shuffle(n int, swap func(i, j int)) {
 | |
| 	if n < 0 {
 | |
| 		panic("invalid argument to Shuffle")
 | |
| 	}
 | |
| 
 | |
| 	// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
 | |
| 	// Shuffle really ought not be called with n that doesn't fit in 32 bits.
 | |
| 	// Not only will it take a very long time, but with 2³¹! possible permutations,
 | |
| 	// there's no way that any PRNG can have a big enough internal state to
 | |
| 	// generate even a minuscule percentage of the possible permutations.
 | |
| 	// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
 | |
| 	i := n - 1
 | |
| 	for ; i > 1<<31-1-1; i-- {
 | |
| 		j := int(r.Int63n(int64(i + 1)))
 | |
| 		swap(i, j)
 | |
| 	}
 | |
| 	for ; i > 0; i-- {
 | |
| 		j := int(r.Int31n(int32(i + 1)))
 | |
| 		swap(i, j)
 | |
| 	}
 | |
| }
 |