...
1
2
3
4
5
6
7 package rand
8
9 import (
10 "encoding/binary"
11 "io"
12 "math/bits"
13 )
14
15
16
17
18
19
20
21
22
23
24
25
26
27 type PCGSource struct {
28 low uint64
29 high uint64
30 }
31
32 const (
33 maxUint32 = (1 << 32) - 1
34
35 multiplier = 47026247687942121848144207491837523525
36 mulHigh = multiplier >> 64
37 mulLow = multiplier & maxUint64
38
39 increment = 117397592171526113268558934119004209487
40 incHigh = increment >> 64
41 incLow = increment & maxUint64
42
43
44 initializer = 245720598905631564143578724636268694099
45 initHigh = initializer >> 64
46 initLow = initializer & maxUint64
47 )
48
49
50 func (pcg *PCGSource) Seed(seed uint64) {
51 pcg.low = seed
52 pcg.high = seed
53 }
54
55
56 func (pcg *PCGSource) Uint64() uint64 {
57 pcg.multiply()
58 pcg.add()
59
60 return bits.RotateLeft64(pcg.high^pcg.low, -int(pcg.high>>58))
61 }
62
63 func (pcg *PCGSource) add() {
64 var carry uint64
65 pcg.low, carry = Add64(pcg.low, incLow, 0)
66 pcg.high, _ = Add64(pcg.high, incHigh, carry)
67 }
68
69 func (pcg *PCGSource) multiply() {
70 hi, lo := Mul64(pcg.low, mulLow)
71 hi += pcg.high * mulLow
72 hi += pcg.low * mulHigh
73 pcg.low = lo
74 pcg.high = hi
75 }
76
77
78 func (pcg *PCGSource) MarshalBinary() ([]byte, error) {
79 var buf [16]byte
80 binary.BigEndian.PutUint64(buf[:8], pcg.high)
81 binary.BigEndian.PutUint64(buf[8:], pcg.low)
82 return buf[:], nil
83 }
84
85
86 func (pcg *PCGSource) UnmarshalBinary(data []byte) error {
87 if len(data) < 16 {
88 return io.ErrUnexpectedEOF
89 }
90 pcg.low = binary.BigEndian.Uint64(data[8:])
91 pcg.high = binary.BigEndian.Uint64(data[:8])
92 return nil
93 }
94
View as plain text