| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package rand |
| |
| import ( |
| "math/big" |
| "math/rand" |
| "testing" |
| ) |
| |
| var bigMaxUint64 = big.NewInt(0).SetUint64(maxUint64) |
| |
| func bigInt(xHi, xLo uint64) *big.Int { |
| b := big.NewInt(0).SetUint64(xHi) |
| b.Lsh(b, 64) |
| b.Or(b, big.NewInt(0).SetUint64(xLo)) |
| return b |
| } |
| |
| func splitBigInt(b *big.Int) (outHi, outLo uint64) { |
| outHi = big.NewInt(0).Rsh(b, 64).Uint64() |
| outLo = big.NewInt(0).And(b, bigMaxUint64).Uint64() |
| return |
| } |
| |
| func bigMulMod128bits(xHi, xLo, yHi, yLo uint64) (outHi, outLo uint64) { |
| bigX := bigInt(xHi, xLo) |
| bigY := bigInt(yHi, yLo) |
| return splitBigInt(bigX.Mul(bigX, bigY)) |
| } |
| |
| func bigAddMod128bits(xHi, xLo, yHi, yLo uint64) (outHi, outLo uint64) { |
| bigX := bigInt(xHi, xLo) |
| bigY := bigInt(yHi, yLo) |
| return splitBigInt(bigX.Add(bigX, bigY)) |
| } |
| |
| type arithTest struct { |
| xHi, xLo uint64 |
| } |
| |
| const ( |
| iLo = increment & maxUint64 |
| iHi = (increment >> 64) & maxUint64 |
| ) |
| |
| var arithTests = []arithTest{ |
| {0, 0}, |
| {0, 1}, |
| {1, 0}, |
| {0, maxUint64}, |
| {maxUint64, 0}, |
| {maxUint64, maxUint64}, |
| // Randomly generated 64-bit integers. |
| {3757956613005209672, 17983933746665545631}, |
| {511324141977587414, 5626651684620191081}, |
| {1534313104606153588, 2415006486399353367}, |
| {6873586429837825902, 13854394671140464137}, |
| {6617134480561088940, 18421520694158684312}, |
| } |
| |
| func TestPCGAdd(t *testing.T) { |
| for i, test := range arithTests { |
| p := &PCGSource{ |
| low: test.xLo, |
| high: test.xHi, |
| } |
| p.add() |
| expectHi, expectLo := bigAddMod128bits(test.xHi, test.xLo, iHi, iLo) |
| if p.low != expectLo || p.high != expectHi { |
| t.Errorf("%d: got hi=%d lo=%d; expect hi=%d lo=%d", i, p.high, p.low, expectHi, expectLo) |
| } |
| } |
| } |
| |
| const ( |
| mLo = multiplier & maxUint64 |
| mHi = (multiplier >> 64) & maxUint64 |
| ) |
| |
| func TestPCGMultiply(t *testing.T) { |
| for i, test := range arithTests { |
| p := &PCGSource{ |
| low: test.xLo, |
| high: test.xHi, |
| } |
| p.multiply() |
| expectHi, expectLo := bigMulMod128bits(test.xHi, test.xLo, mHi, mLo) |
| if p.low != expectLo || p.high != expectHi { |
| t.Errorf("%d: got hi=%d lo=%d; expect hi=%d lo=%d", i, p.high, p.low, expectHi, expectLo) |
| } |
| } |
| } |
| |
| func TestPCGMultiplyLong(t *testing.T) { |
| if testing.Short() { |
| return |
| } |
| for i := 0; i < 1e6; i++ { |
| low := rand.Uint64() |
| high := rand.Uint64() |
| p := &PCGSource{ |
| low: low, |
| high: high, |
| } |
| p.multiply() |
| expectHi, expectLo := bigMulMod128bits(high, low, mHi, mLo) |
| if p.low != expectLo || p.high != expectHi { |
| t.Fatalf("%d: (%d,%d): got hi=%d lo=%d; expect hi=%d lo=%d", i, high, low, p.high, p.low, expectHi, expectLo) |
| } |
| } |
| } |
| |
| func BenchmarkPCGMultiply(b *testing.B) { |
| low := rand.Uint64() |
| high := rand.Uint64() |
| p := &PCGSource{ |
| low: low, |
| high: high, |
| } |
| for i := 0; i < b.N; i++ { |
| p.multiply() |
| } |
| } |