golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/rand/arith128_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 // Randomly generated 64-bit integers. 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 }