/
rand.go
50 lines (43 loc) · 946 Bytes
/
rand.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package otk
import (
"math/rand"
"runtime"
"sync/atomic"
"time"
"unsafe"
)
var _ rand.Source = (*XorShiftRNG)(nil)
// XorShiftRNG simple efficient thread-safe lock-free rng, self seeds with time.Now().UnixNano() if 0
type XorShiftRNG uint64
func (x *XorShiftRNG) Seed(n int64) {
nx := XorShiftRNG(n)
atomic.StoreUint64((*uint64)(x), nx.Uint64())
}
func (x *XorShiftRNG) Uint64() (rv uint64) {
RETRY:
a := atomic.LoadUint64((*uint64)(x))
if a != 0 {
rv = a | 0xCAFEBABE
} else {
rv = uint64(time.Now().UnixNano()) | 0xCAFEBABE
}
rv = rv ^ (rv << 21)
rv = rv ^ (rv >> 35)
rv = rv ^ (a << 4)
if !atomic.CompareAndSwapUint64((*uint64)(x), a, rv) {
runtime.Gosched()
goto RETRY
}
return
}
func (x *XorShiftRNG) Int63() int64 {
const (
rngMax = 1 << 63
rngMask = rngMax - 1
)
return int64(x.Uint64() & rngMask)
}
func (x *XorShiftRNG) Bytes() [8]byte {
n := x.Uint64()
return *(*[8]byte)(unsafe.Pointer(&n))
}