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