tracker/pkg/xorshift/xorshift.go
2017-06-12 22:07:05 +02:00

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
}