71 lines
1.7 KiB
Go
71 lines
1.7 KiB
Go
// Package xorshift implements the XORShift PRNG.
|
|
package xorshift
|
|
|
|
import "sync"
|
|
|
|
// XORShift describes the functionality of an XORShift PRNG.
|
|
type XORShift interface {
|
|
Next() uint64
|
|
}
|
|
|
|
// XORShift128Plus holds the state of an XORShift128Plus PRNG.
|
|
type XORShift128Plus struct {
|
|
state [2]uint64
|
|
}
|
|
|
|
// Next generates a pseudorandom number and advances the state of s.
|
|
func (s *XORShift128Plus) Next() uint64 {
|
|
s1 := s.state[0]
|
|
s0 := s.state[1]
|
|
s1Tmp := s1 // need this for result computation
|
|
s.state[0] = s0
|
|
s1 ^= (s1 << 23) // a
|
|
s.state[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5) // b, c
|
|
return s0 + s1Tmp
|
|
}
|
|
|
|
// NewXORShift128Plus creates a new XORShift PRNG.
|
|
func NewXORShift128Plus(s0, s1 uint64) *XORShift128Plus {
|
|
return &XORShift128Plus{
|
|
state: [2]uint64{s0, s1},
|
|
}
|
|
}
|
|
|
|
// LockedXORShift128Plus is a thread-safe XORShift128Plus.
|
|
type LockedXORShift128Plus struct {
|
|
sync.Mutex
|
|
state [2]uint64
|
|
}
|
|
|
|
// NewLockedXORShift128Plus creates a new LockedXORShift128Plus.
|
|
func NewLockedXORShift128Plus(s0, s1 uint64) *LockedXORShift128Plus {
|
|
return &LockedXORShift128Plus{
|
|
state: [2]uint64{s0, s1},
|
|
}
|
|
}
|
|
|
|
// Next generates a pseudorandom number and advances the state of s.
|
|
func (s *LockedXORShift128Plus) Next() uint64 {
|
|
s.Lock()
|
|
s1 := s.state[0]
|
|
s0 := s.state[1]
|
|
s1Tmp := s1 // need this for result computation
|
|
s.state[0] = s0
|
|
s1 ^= (s1 << 23) // a
|
|
s.state[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5) // b, c
|
|
s.Unlock()
|
|
return s0 + s1Tmp
|
|
}
|
|
|
|
// Intn generates an int k that satisfies k >= 0 && k < n.
|
|
// n must be > 0.
|
|
func Intn(s XORShift, n int) int {
|
|
if n <= 0 {
|
|
panic("invalid n <= 0")
|
|
}
|
|
v := int(s.Next())
|
|
if v < 0 {
|
|
v = -v
|
|
}
|
|
return v % n
|
|
}
|