pgregory.net/rand@v1.0.3-0.20230808192358-a0b8ce02f4da/global_test.go (about)

     1  // Copyright 2022 Gregory Petrosyan <gregory.petrosyan@gmail.com>
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, v. 2.0. If a copy of the MPL was not distributed with this
     5  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
     6  
     7  package rand_test
     8  
     9  import (
    10  	"math"
    11  	"math/bits"
    12  	"pgregory.net/rand"
    13  	"pgregory.net/rapid"
    14  	"sync/atomic"
    15  	"testing"
    16  )
    17  
    18  const (
    19  	wyrandAdd = 0xa0761d6478bd642f
    20  	wyrandXor = 0xe7037ed1a0b428db
    21  )
    22  
    23  func wyrand64(state *uint64) uint64 {
    24  	s := *state + wyrandAdd
    25  	*state = s
    26  	hi, lo := bits.Mul64(s, s^wyrandXor)
    27  	return hi ^ lo
    28  }
    29  
    30  func wyrand64Atomic(state *uint64) uint64 {
    31  	s := atomic.AddUint64(state, wyrandAdd)
    32  	hi, lo := bits.Mul64(s, s^wyrandXor)
    33  	return hi ^ lo
    34  }
    35  
    36  func BenchmarkRand64(b *testing.B) {
    37  	var s uint64
    38  	for i := 0; i < b.N; i++ {
    39  		s = rand.Uint64()
    40  	}
    41  	sinkUint64 = s
    42  }
    43  
    44  func BenchmarkWyRand64(b *testing.B) {
    45  	var s uint64
    46  	var state uint64
    47  	for i := 0; i < b.N; i++ {
    48  		s = wyrand64(&state)
    49  	}
    50  	sinkUint64 = s
    51  }
    52  
    53  func BenchmarkWyRand64Atomic(b *testing.B) {
    54  	var s uint64
    55  	var state uint64
    56  	for i := 0; i < b.N; i++ {
    57  		s = wyrand64Atomic(&state)
    58  	}
    59  	sinkUint64 = s
    60  }
    61  
    62  func TestFloat32(t *testing.T) {
    63  	rapid.Check(t, func(t *rapid.T) {
    64  		f := rand.Float32()
    65  		if f < 0 || f >= 1 {
    66  			t.Fatalf("got %v outside of [0, 1)", f)
    67  		}
    68  	})
    69  }
    70  
    71  func TestFloat64(t *testing.T) {
    72  	rapid.Check(t, func(t *rapid.T) {
    73  		f := rand.Float64()
    74  		if f < 0 || f >= 1 {
    75  			t.Fatalf("got %v outside of [0, 1)", f)
    76  		}
    77  	})
    78  }
    79  
    80  func TestInt31n(t *testing.T) {
    81  	rapid.Check(t, func(t *rapid.T) {
    82  		n := rapid.Int32Range(1, math.MaxInt32).Draw(t, "n").(int32)
    83  		v := rand.Int31n(n)
    84  		if v < 0 || v >= n {
    85  			t.Fatalf("got %v outside of [0, %v)", v, n)
    86  		}
    87  	})
    88  }
    89  
    90  func TestInt63n(t *testing.T) {
    91  	rapid.Check(t, func(t *rapid.T) {
    92  		n := rapid.Int64Range(1, math.MaxInt64).Draw(t, "n").(int64)
    93  		v := rand.Int63n(n)
    94  		if v < 0 || v >= n {
    95  			t.Fatalf("got %v outside of [0, %v)", v, n)
    96  		}
    97  	})
    98  }
    99  
   100  func TestIntn(t *testing.T) {
   101  	rapid.Check(t, func(t *rapid.T) {
   102  		n := rapid.IntRange(1, math.MaxInt).Draw(t, "n").(int)
   103  		v := rand.Intn(n)
   104  		if v < 0 || v >= n {
   105  			t.Fatalf("got %v outside of [0, %v)", v, n)
   106  		}
   107  	})
   108  }
   109  
   110  func TestUint32n(t *testing.T) {
   111  	rapid.Check(t, func(t *rapid.T) {
   112  		n := rapid.Uint32Range(1, math.MaxUint32).Draw(t, "n").(uint32)
   113  		v := rand.Uint32n(n)
   114  		if v >= n {
   115  			t.Fatalf("got %v outside of [0, %v)", v, n)
   116  		}
   117  	})
   118  }
   119  
   120  func TestUint64n(t *testing.T) {
   121  	rapid.Check(t, func(t *rapid.T) {
   122  		n := rapid.Uint64Range(1, math.MaxUint64).Draw(t, "n").(uint64)
   123  		v := rand.Uint64n(n)
   124  		if v >= n {
   125  			t.Fatalf("got %v outside of [0, %v)", v, n)
   126  		}
   127  	})
   128  }