1
2
3
4
5 package rand
6
7 import (
8 "math/big"
9 "math/rand"
10 "testing"
11 )
12
13 var bigMaxUint64 = big.NewInt(0).SetUint64(maxUint64)
14
15 func bigInt(xHi, xLo uint64) *big.Int {
16 b := big.NewInt(0).SetUint64(xHi)
17 b.Lsh(b, 64)
18 b.Or(b, big.NewInt(0).SetUint64(xLo))
19 return b
20 }
21
22 func splitBigInt(b *big.Int) (outHi, outLo uint64) {
23 outHi = big.NewInt(0).Rsh(b, 64).Uint64()
24 outLo = big.NewInt(0).And(b, bigMaxUint64).Uint64()
25 return
26 }
27
28 func bigMulMod128bits(xHi, xLo, yHi, yLo uint64) (outHi, outLo uint64) {
29 bigX := bigInt(xHi, xLo)
30 bigY := bigInt(yHi, yLo)
31 return splitBigInt(bigX.Mul(bigX, bigY))
32 }
33
34 func bigAddMod128bits(xHi, xLo, yHi, yLo uint64) (outHi, outLo uint64) {
35 bigX := bigInt(xHi, xLo)
36 bigY := bigInt(yHi, yLo)
37 return splitBigInt(bigX.Add(bigX, bigY))
38 }
39
40 type arithTest struct {
41 xHi, xLo uint64
42 }
43
44 const (
45 iLo = increment & maxUint64
46 iHi = (increment >> 64) & maxUint64
47 )
48
49 var arithTests = []arithTest{
50 {0, 0},
51 {0, 1},
52 {1, 0},
53 {0, maxUint64},
54 {maxUint64, 0},
55 {maxUint64, maxUint64},
56
57 {3757956613005209672, 17983933746665545631},
58 {511324141977587414, 5626651684620191081},
59 {1534313104606153588, 2415006486399353367},
60 {6873586429837825902, 13854394671140464137},
61 {6617134480561088940, 18421520694158684312},
62 }
63
64 func TestPCGAdd(t *testing.T) {
65 for i, test := range arithTests {
66 p := &PCGSource{
67 low: test.xLo,
68 high: test.xHi,
69 }
70 p.add()
71 expectHi, expectLo := bigAddMod128bits(test.xHi, test.xLo, iHi, iLo)
72 if p.low != expectLo || p.high != expectHi {
73 t.Errorf("%d: got hi=%d lo=%d; expect hi=%d lo=%d", i, p.high, p.low, expectHi, expectLo)
74 }
75 }
76 }
77
78 const (
79 mLo = multiplier & maxUint64
80 mHi = (multiplier >> 64) & maxUint64
81 )
82
83 func TestPCGMultiply(t *testing.T) {
84 for i, test := range arithTests {
85 p := &PCGSource{
86 low: test.xLo,
87 high: test.xHi,
88 }
89 p.multiply()
90 expectHi, expectLo := bigMulMod128bits(test.xHi, test.xLo, mHi, mLo)
91 if p.low != expectLo || p.high != expectHi {
92 t.Errorf("%d: got hi=%d lo=%d; expect hi=%d lo=%d", i, p.high, p.low, expectHi, expectLo)
93 }
94 }
95 }
96
97 func TestPCGMultiplyLong(t *testing.T) {
98 if testing.Short() {
99 return
100 }
101 for i := 0; i < 1e6; i++ {
102 low := rand.Uint64()
103 high := rand.Uint64()
104 p := &PCGSource{
105 low: low,
106 high: high,
107 }
108 p.multiply()
109 expectHi, expectLo := bigMulMod128bits(high, low, mHi, mLo)
110 if p.low != expectLo || p.high != expectHi {
111 t.Fatalf("%d: (%d,%d): got hi=%d lo=%d; expect hi=%d lo=%d", i, high, low, p.high, p.low, expectHi, expectLo)
112 }
113 }
114 }
115
116 func BenchmarkPCGMultiply(b *testing.B) {
117 low := rand.Uint64()
118 high := rand.Uint64()
119 p := &PCGSource{
120 low: low,
121 high: high,
122 }
123 for i := 0; i < b.N; i++ {
124 p.multiply()
125 }
126 }
127
View as plain text