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  }