Source file src/math/rand/v2/rand_test.go

     1  // Copyright 2009 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_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"math"
    12  	. "math/rand/v2"
    13  	"os"
    14  	"runtime"
    15  	"sync"
    16  	"sync/atomic"
    17  	"testing"
    18  )
    19  
    20  const (
    21  	numTestSamples = 10000
    22  )
    23  
    24  var rn, kn, wn, fn = GetNormalDistributionParameters()
    25  var re, ke, we, fe = GetExponentialDistributionParameters()
    26  
    27  type statsResults struct {
    28  	mean        float64
    29  	stddev      float64
    30  	closeEnough float64
    31  	maxError    float64
    32  }
    33  
    34  func max(a, b float64) float64 {
    35  	if a > b {
    36  		return a
    37  	}
    38  	return b
    39  }
    40  
    41  func nearEqual(a, b, closeEnough, maxError float64) bool {
    42  	absDiff := math.Abs(a - b)
    43  	if absDiff < closeEnough { // Necessary when one value is zero and one value is close to zero.
    44  		return true
    45  	}
    46  	return absDiff/max(math.Abs(a), math.Abs(b)) < maxError
    47  }
    48  
    49  var testSeeds = []uint64{1, 1754801282, 1698661970, 1550503961}
    50  
    51  // checkSimilarDistribution returns success if the mean and stddev of the
    52  // two statsResults are similar.
    53  func (sr *statsResults) checkSimilarDistribution(expected *statsResults) error {
    54  	if !nearEqual(sr.mean, expected.mean, expected.closeEnough, expected.maxError) {
    55  		s := fmt.Sprintf("mean %v != %v (allowed error %v, %v)", sr.mean, expected.mean, expected.closeEnough, expected.maxError)
    56  		fmt.Println(s)
    57  		return errors.New(s)
    58  	}
    59  	if !nearEqual(sr.stddev, expected.stddev, expected.closeEnough, expected.maxError) {
    60  		s := fmt.Sprintf("stddev %v != %v (allowed error %v, %v)", sr.stddev, expected.stddev, expected.closeEnough, expected.maxError)
    61  		fmt.Println(s)
    62  		return errors.New(s)
    63  	}
    64  	return nil
    65  }
    66  
    67  func getStatsResults(samples []float64) *statsResults {
    68  	res := new(statsResults)
    69  	var sum, squaresum float64
    70  	for _, s := range samples {
    71  		sum += s
    72  		squaresum += s * s
    73  	}
    74  	res.mean = sum / float64(len(samples))
    75  	res.stddev = math.Sqrt(squaresum/float64(len(samples)) - res.mean*res.mean)
    76  	return res
    77  }
    78  
    79  func checkSampleDistribution(t *testing.T, samples []float64, expected *statsResults) {
    80  	t.Helper()
    81  	actual := getStatsResults(samples)
    82  	err := actual.checkSimilarDistribution(expected)
    83  	if err != nil {
    84  		t.Errorf(err.Error())
    85  	}
    86  }
    87  
    88  func checkSampleSliceDistributions(t *testing.T, samples []float64, nslices int, expected *statsResults) {
    89  	t.Helper()
    90  	chunk := len(samples) / nslices
    91  	for i := 0; i < nslices; i++ {
    92  		low := i * chunk
    93  		var high int
    94  		if i == nslices-1 {
    95  			high = len(samples) - 1
    96  		} else {
    97  			high = (i + 1) * chunk
    98  		}
    99  		checkSampleDistribution(t, samples[low:high], expected)
   100  	}
   101  }
   102  
   103  //
   104  // Normal distribution tests
   105  //
   106  
   107  func generateNormalSamples(nsamples int, mean, stddev float64, seed uint64) []float64 {
   108  	r := New(NewPCG(seed, seed))
   109  	samples := make([]float64, nsamples)
   110  	for i := range samples {
   111  		samples[i] = r.NormFloat64()*stddev + mean
   112  	}
   113  	return samples
   114  }
   115  
   116  func testNormalDistribution(t *testing.T, nsamples int, mean, stddev float64, seed uint64) {
   117  	//fmt.Printf("testing nsamples=%v mean=%v stddev=%v seed=%v\n", nsamples, mean, stddev, seed);
   118  
   119  	samples := generateNormalSamples(nsamples, mean, stddev, seed)
   120  	errorScale := max(1.0, stddev) // Error scales with stddev
   121  	expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale}
   122  
   123  	// Make sure that the entire set matches the expected distribution.
   124  	checkSampleDistribution(t, samples, expected)
   125  
   126  	// Make sure that each half of the set matches the expected distribution.
   127  	checkSampleSliceDistributions(t, samples, 2, expected)
   128  
   129  	// Make sure that each 7th of the set matches the expected distribution.
   130  	checkSampleSliceDistributions(t, samples, 7, expected)
   131  }
   132  
   133  // Actual tests
   134  
   135  func TestStandardNormalValues(t *testing.T) {
   136  	for _, seed := range testSeeds {
   137  		testNormalDistribution(t, numTestSamples, 0, 1, seed)
   138  	}
   139  }
   140  
   141  func TestNonStandardNormalValues(t *testing.T) {
   142  	sdmax := 1000.0
   143  	mmax := 1000.0
   144  	if testing.Short() {
   145  		sdmax = 5
   146  		mmax = 5
   147  	}
   148  	for sd := 0.5; sd < sdmax; sd *= 2 {
   149  		for m := 0.5; m < mmax; m *= 2 {
   150  			for _, seed := range testSeeds {
   151  				testNormalDistribution(t, numTestSamples, m, sd, seed)
   152  				if testing.Short() {
   153  					break
   154  				}
   155  			}
   156  		}
   157  	}
   158  }
   159  
   160  //
   161  // Exponential distribution tests
   162  //
   163  
   164  func generateExponentialSamples(nsamples int, rate float64, seed uint64) []float64 {
   165  	r := New(NewPCG(seed, seed))
   166  	samples := make([]float64, nsamples)
   167  	for i := range samples {
   168  		samples[i] = r.ExpFloat64() / rate
   169  	}
   170  	return samples
   171  }
   172  
   173  func testExponentialDistribution(t *testing.T, nsamples int, rate float64, seed uint64) {
   174  	//fmt.Printf("testing nsamples=%v rate=%v seed=%v\n", nsamples, rate, seed);
   175  
   176  	mean := 1 / rate
   177  	stddev := mean
   178  
   179  	samples := generateExponentialSamples(nsamples, rate, seed)
   180  	errorScale := max(1.0, 1/rate) // Error scales with the inverse of the rate
   181  	expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.20 * errorScale}
   182  
   183  	// Make sure that the entire set matches the expected distribution.
   184  	checkSampleDistribution(t, samples, expected)
   185  
   186  	// Make sure that each half of the set matches the expected distribution.
   187  	checkSampleSliceDistributions(t, samples, 2, expected)
   188  
   189  	// Make sure that each 7th of the set matches the expected distribution.
   190  	checkSampleSliceDistributions(t, samples, 7, expected)
   191  }
   192  
   193  // Actual tests
   194  
   195  func TestStandardExponentialValues(t *testing.T) {
   196  	for _, seed := range testSeeds {
   197  		testExponentialDistribution(t, numTestSamples, 1, seed)
   198  	}
   199  }
   200  
   201  func TestNonStandardExponentialValues(t *testing.T) {
   202  	for rate := 0.05; rate < 10; rate *= 2 {
   203  		for _, seed := range testSeeds {
   204  			testExponentialDistribution(t, numTestSamples, rate, seed)
   205  			if testing.Short() {
   206  				break
   207  			}
   208  		}
   209  	}
   210  }
   211  
   212  //
   213  // Table generation tests
   214  //
   215  
   216  func initNorm() (testKn []uint32, testWn, testFn []float32) {
   217  	const m1 = 1 << 31
   218  	var (
   219  		dn float64 = rn
   220  		tn         = dn
   221  		vn float64 = 9.91256303526217e-3
   222  	)
   223  
   224  	testKn = make([]uint32, 128)
   225  	testWn = make([]float32, 128)
   226  	testFn = make([]float32, 128)
   227  
   228  	q := vn / math.Exp(-0.5*dn*dn)
   229  	testKn[0] = uint32((dn / q) * m1)
   230  	testKn[1] = 0
   231  	testWn[0] = float32(q / m1)
   232  	testWn[127] = float32(dn / m1)
   233  	testFn[0] = 1.0
   234  	testFn[127] = float32(math.Exp(-0.5 * dn * dn))
   235  	for i := 126; i >= 1; i-- {
   236  		dn = math.Sqrt(-2.0 * math.Log(vn/dn+math.Exp(-0.5*dn*dn)))
   237  		testKn[i+1] = uint32((dn / tn) * m1)
   238  		tn = dn
   239  		testFn[i] = float32(math.Exp(-0.5 * dn * dn))
   240  		testWn[i] = float32(dn / m1)
   241  	}
   242  	return
   243  }
   244  
   245  func initExp() (testKe []uint32, testWe, testFe []float32) {
   246  	const m2 = 1 << 32
   247  	var (
   248  		de float64 = re
   249  		te         = de
   250  		ve float64 = 3.9496598225815571993e-3
   251  	)
   252  
   253  	testKe = make([]uint32, 256)
   254  	testWe = make([]float32, 256)
   255  	testFe = make([]float32, 256)
   256  
   257  	q := ve / math.Exp(-de)
   258  	testKe[0] = uint32((de / q) * m2)
   259  	testKe[1] = 0
   260  	testWe[0] = float32(q / m2)
   261  	testWe[255] = float32(de / m2)
   262  	testFe[0] = 1.0
   263  	testFe[255] = float32(math.Exp(-de))
   264  	for i := 254; i >= 1; i-- {
   265  		de = -math.Log(ve/de + math.Exp(-de))
   266  		testKe[i+1] = uint32((de / te) * m2)
   267  		te = de
   268  		testFe[i] = float32(math.Exp(-de))
   269  		testWe[i] = float32(de / m2)
   270  	}
   271  	return
   272  }
   273  
   274  // compareUint32Slices returns the first index where the two slices
   275  // disagree, or <0 if the lengths are the same and all elements
   276  // are identical.
   277  func compareUint32Slices(s1, s2 []uint32) int {
   278  	if len(s1) != len(s2) {
   279  		if len(s1) > len(s2) {
   280  			return len(s2) + 1
   281  		}
   282  		return len(s1) + 1
   283  	}
   284  	for i := range s1 {
   285  		if s1[i] != s2[i] {
   286  			return i
   287  		}
   288  	}
   289  	return -1
   290  }
   291  
   292  // compareFloat32Slices returns the first index where the two slices
   293  // disagree, or <0 if the lengths are the same and all elements
   294  // are identical.
   295  func compareFloat32Slices(s1, s2 []float32) int {
   296  	if len(s1) != len(s2) {
   297  		if len(s1) > len(s2) {
   298  			return len(s2) + 1
   299  		}
   300  		return len(s1) + 1
   301  	}
   302  	for i := range s1 {
   303  		if !nearEqual(float64(s1[i]), float64(s2[i]), 0, 1e-7) {
   304  			return i
   305  		}
   306  	}
   307  	return -1
   308  }
   309  
   310  func TestNormTables(t *testing.T) {
   311  	testKn, testWn, testFn := initNorm()
   312  	if i := compareUint32Slices(kn[0:], testKn); i >= 0 {
   313  		t.Errorf("kn disagrees at index %v; %v != %v", i, kn[i], testKn[i])
   314  	}
   315  	if i := compareFloat32Slices(wn[0:], testWn); i >= 0 {
   316  		t.Errorf("wn disagrees at index %v; %v != %v", i, wn[i], testWn[i])
   317  	}
   318  	if i := compareFloat32Slices(fn[0:], testFn); i >= 0 {
   319  		t.Errorf("fn disagrees at index %v; %v != %v", i, fn[i], testFn[i])
   320  	}
   321  }
   322  
   323  func TestExpTables(t *testing.T) {
   324  	testKe, testWe, testFe := initExp()
   325  	if i := compareUint32Slices(ke[0:], testKe); i >= 0 {
   326  		t.Errorf("ke disagrees at index %v; %v != %v", i, ke[i], testKe[i])
   327  	}
   328  	if i := compareFloat32Slices(we[0:], testWe); i >= 0 {
   329  		t.Errorf("we disagrees at index %v; %v != %v", i, we[i], testWe[i])
   330  	}
   331  	if i := compareFloat32Slices(fe[0:], testFe); i >= 0 {
   332  		t.Errorf("fe disagrees at index %v; %v != %v", i, fe[i], testFe[i])
   333  	}
   334  }
   335  
   336  func hasSlowFloatingPoint() bool {
   337  	switch runtime.GOARCH {
   338  	case "arm":
   339  		return os.Getenv("GOARM") == "5"
   340  	case "mips", "mipsle", "mips64", "mips64le":
   341  		// Be conservative and assume that all mips boards
   342  		// have emulated floating point.
   343  		// TODO: detect what it actually has.
   344  		return true
   345  	}
   346  	return false
   347  }
   348  
   349  func TestFloat32(t *testing.T) {
   350  	// For issue 6721, the problem came after 7533753 calls, so check 10e6.
   351  	num := int(10e6)
   352  	// But do the full amount only on builders (not locally).
   353  	// But ARM5 floating point emulation is slow (Issue 10749), so
   354  	// do less for that builder:
   355  	if testing.Short() && (testenv.Builder() == "" || hasSlowFloatingPoint()) {
   356  		num /= 100 // 1.72 seconds instead of 172 seconds
   357  	}
   358  
   359  	r := testRand()
   360  	for ct := 0; ct < num; ct++ {
   361  		f := r.Float32()
   362  		if f >= 1 {
   363  			t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
   364  		}
   365  	}
   366  }
   367  
   368  func TestShuffleSmall(t *testing.T) {
   369  	// Check that Shuffle allows n=0 and n=1, but that swap is never called for them.
   370  	r := testRand()
   371  	for n := 0; n <= 1; n++ {
   372  		r.Shuffle(n, func(i, j int) { t.Fatalf("swap called, n=%d i=%d j=%d", n, i, j) })
   373  	}
   374  }
   375  
   376  // encodePerm converts from a permuted slice of length n, such as Perm generates, to an int in [0, n!).
   377  // See https://en.wikipedia.org/wiki/Lehmer_code.
   378  // encodePerm modifies the input slice.
   379  func encodePerm(s []int) int {
   380  	// Convert to Lehmer code.
   381  	for i, x := range s {
   382  		r := s[i+1:]
   383  		for j, y := range r {
   384  			if y > x {
   385  				r[j]--
   386  			}
   387  		}
   388  	}
   389  	// Convert to int in [0, n!).
   390  	m := 0
   391  	fact := 1
   392  	for i := len(s) - 1; i >= 0; i-- {
   393  		m += s[i] * fact
   394  		fact *= len(s) - i
   395  	}
   396  	return m
   397  }
   398  
   399  // TestUniformFactorial tests several ways of generating a uniform value in [0, n!).
   400  func TestUniformFactorial(t *testing.T) {
   401  	r := New(NewPCG(1, 2))
   402  	top := 6
   403  	if testing.Short() {
   404  		top = 3
   405  	}
   406  	for n := 3; n <= top; n++ {
   407  		t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) {
   408  			// Calculate n!.
   409  			nfact := 1
   410  			for i := 2; i <= n; i++ {
   411  				nfact *= i
   412  			}
   413  
   414  			// Test a few different ways to generate a uniform distribution.
   415  			p := make([]int, n) // re-usable slice for Shuffle generator
   416  			tests := [...]struct {
   417  				name string
   418  				fn   func() int
   419  			}{
   420  				{name: "Int32N", fn: func() int { return int(r.Int32N(int32(nfact))) }},
   421  				{name: "Perm", fn: func() int { return encodePerm(r.Perm(n)) }},
   422  				{name: "Shuffle", fn: func() int {
   423  					// Generate permutation using Shuffle.
   424  					for i := range p {
   425  						p[i] = i
   426  					}
   427  					r.Shuffle(n, func(i, j int) { p[i], p[j] = p[j], p[i] })
   428  					return encodePerm(p)
   429  				}},
   430  			}
   431  
   432  			for _, test := range tests {
   433  				t.Run(test.name, func(t *testing.T) {
   434  					// Gather chi-squared values and check that they follow
   435  					// the expected normal distribution given n!-1 degrees of freedom.
   436  					// See https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test and
   437  					// https://www.johndcook.com/Beautiful_Testing_ch10.pdf.
   438  					nsamples := 10 * nfact
   439  					if nsamples < 1000 {
   440  						nsamples = 1000
   441  					}
   442  					samples := make([]float64, nsamples)
   443  					for i := range samples {
   444  						// Generate some uniformly distributed values and count their occurrences.
   445  						const iters = 1000
   446  						counts := make([]int, nfact)
   447  						for i := 0; i < iters; i++ {
   448  							counts[test.fn()]++
   449  						}
   450  						// Calculate chi-squared and add to samples.
   451  						want := iters / float64(nfact)
   452  						var χ2 float64
   453  						for _, have := range counts {
   454  							err := float64(have) - want
   455  							χ2 += err * err
   456  						}
   457  						χ2 /= want
   458  						samples[i] = χ2
   459  					}
   460  
   461  					// Check that our samples approximate the appropriate normal distribution.
   462  					dof := float64(nfact - 1)
   463  					expected := &statsResults{mean: dof, stddev: math.Sqrt(2 * dof)}
   464  					errorScale := max(1.0, expected.stddev)
   465  					expected.closeEnough = 0.10 * errorScale
   466  					expected.maxError = 0.08 // TODO: What is the right value here? See issue 21211.
   467  					checkSampleDistribution(t, samples, expected)
   468  				})
   469  			}
   470  		})
   471  	}
   472  }
   473  
   474  // Benchmarks
   475  
   476  var Sink uint64
   477  
   478  func testRand() *Rand {
   479  	return New(NewPCG(1, 2))
   480  }
   481  
   482  func BenchmarkSourceUint64(b *testing.B) {
   483  	s := NewPCG(1, 2)
   484  	var t uint64
   485  	for n := b.N; n > 0; n-- {
   486  		t += s.Uint64()
   487  	}
   488  	Sink = uint64(t)
   489  }
   490  
   491  func BenchmarkGlobalInt64(b *testing.B) {
   492  	var t int64
   493  	for n := b.N; n > 0; n-- {
   494  		t += Int64()
   495  	}
   496  	Sink = uint64(t)
   497  }
   498  
   499  func BenchmarkGlobalInt64Parallel(b *testing.B) {
   500  	b.RunParallel(func(pb *testing.PB) {
   501  		var t int64
   502  		for pb.Next() {
   503  			t += Int64()
   504  		}
   505  		atomic.AddUint64(&Sink, uint64(t))
   506  	})
   507  }
   508  
   509  func BenchmarkGlobalUint64(b *testing.B) {
   510  	var t uint64
   511  	for n := b.N; n > 0; n-- {
   512  		t += Uint64()
   513  	}
   514  	Sink = t
   515  }
   516  
   517  func BenchmarkGlobalUint64Parallel(b *testing.B) {
   518  	b.RunParallel(func(pb *testing.PB) {
   519  		var t uint64
   520  		for pb.Next() {
   521  			t += Uint64()
   522  		}
   523  		atomic.AddUint64(&Sink, t)
   524  	})
   525  }
   526  
   527  func BenchmarkInt64(b *testing.B) {
   528  	r := testRand()
   529  	var t int64
   530  	for n := b.N; n > 0; n-- {
   531  		t += r.Int64()
   532  	}
   533  	Sink = uint64(t)
   534  }
   535  
   536  var AlwaysFalse = false
   537  
   538  func keep[T int | uint | int32 | uint32 | int64 | uint64](x T) T {
   539  	if AlwaysFalse {
   540  		return -x
   541  	}
   542  	return x
   543  }
   544  
   545  func BenchmarkUint64(b *testing.B) {
   546  	r := testRand()
   547  	var t uint64
   548  	for n := b.N; n > 0; n-- {
   549  		t += r.Uint64()
   550  	}
   551  	Sink = t
   552  }
   553  
   554  func BenchmarkGlobalIntN1000(b *testing.B) {
   555  	var t int
   556  	arg := keep(1000)
   557  	for n := b.N; n > 0; n-- {
   558  		t += IntN(arg)
   559  	}
   560  	Sink = uint64(t)
   561  }
   562  
   563  func BenchmarkIntN1000(b *testing.B) {
   564  	r := testRand()
   565  	var t int
   566  	arg := keep(1000)
   567  	for n := b.N; n > 0; n-- {
   568  		t += r.IntN(arg)
   569  	}
   570  	Sink = uint64(t)
   571  }
   572  
   573  func BenchmarkInt64N1000(b *testing.B) {
   574  	r := testRand()
   575  	var t int64
   576  	arg := keep(int64(1000))
   577  	for n := b.N; n > 0; n-- {
   578  		t += r.Int64N(arg)
   579  	}
   580  	Sink = uint64(t)
   581  }
   582  
   583  func BenchmarkInt64N1e8(b *testing.B) {
   584  	r := testRand()
   585  	var t int64
   586  	arg := keep(int64(1e8))
   587  	for n := b.N; n > 0; n-- {
   588  		t += r.Int64N(arg)
   589  	}
   590  	Sink = uint64(t)
   591  }
   592  
   593  func BenchmarkInt64N1e9(b *testing.B) {
   594  	r := testRand()
   595  	var t int64
   596  	arg := keep(int64(1e9))
   597  	for n := b.N; n > 0; n-- {
   598  		t += r.Int64N(arg)
   599  	}
   600  	Sink = uint64(t)
   601  }
   602  
   603  func BenchmarkInt64N2e9(b *testing.B) {
   604  	r := testRand()
   605  	var t int64
   606  	arg := keep(int64(2e9))
   607  	for n := b.N; n > 0; n-- {
   608  		t += r.Int64N(arg)
   609  	}
   610  	Sink = uint64(t)
   611  }
   612  
   613  func BenchmarkInt64N1e18(b *testing.B) {
   614  	r := testRand()
   615  	var t int64
   616  	arg := keep(int64(1e18))
   617  	for n := b.N; n > 0; n-- {
   618  		t += r.Int64N(arg)
   619  	}
   620  	Sink = uint64(t)
   621  }
   622  
   623  func BenchmarkInt64N2e18(b *testing.B) {
   624  	r := testRand()
   625  	var t int64
   626  	arg := keep(int64(2e18))
   627  	for n := b.N; n > 0; n-- {
   628  		t += r.Int64N(arg)
   629  	}
   630  	Sink = uint64(t)
   631  }
   632  
   633  func BenchmarkInt64N4e18(b *testing.B) {
   634  	r := testRand()
   635  	var t int64
   636  	arg := keep(int64(4e18))
   637  	for n := b.N; n > 0; n-- {
   638  		t += r.Int64N(arg)
   639  	}
   640  	Sink = uint64(t)
   641  }
   642  
   643  func BenchmarkInt32N1000(b *testing.B) {
   644  	r := testRand()
   645  	var t int32
   646  	arg := keep(int32(1000))
   647  	for n := b.N; n > 0; n-- {
   648  		t += r.Int32N(arg)
   649  	}
   650  	Sink = uint64(t)
   651  }
   652  
   653  func BenchmarkInt32N1e8(b *testing.B) {
   654  	r := testRand()
   655  	var t int32
   656  	arg := keep(int32(1e8))
   657  	for n := b.N; n > 0; n-- {
   658  		t += r.Int32N(arg)
   659  	}
   660  	Sink = uint64(t)
   661  }
   662  
   663  func BenchmarkInt32N1e9(b *testing.B) {
   664  	r := testRand()
   665  	var t int32
   666  	arg := keep(int32(1e9))
   667  	for n := b.N; n > 0; n-- {
   668  		t += r.Int32N(arg)
   669  	}
   670  	Sink = uint64(t)
   671  }
   672  
   673  func BenchmarkInt32N2e9(b *testing.B) {
   674  	r := testRand()
   675  	var t int32
   676  	arg := keep(int32(2e9))
   677  	for n := b.N; n > 0; n-- {
   678  		t += r.Int32N(arg)
   679  	}
   680  	Sink = uint64(t)
   681  }
   682  
   683  func BenchmarkFloat32(b *testing.B) {
   684  	r := testRand()
   685  	var t float32
   686  	for n := b.N; n > 0; n-- {
   687  		t += r.Float32()
   688  	}
   689  	Sink = uint64(t)
   690  }
   691  
   692  func BenchmarkFloat64(b *testing.B) {
   693  	r := testRand()
   694  	var t float64
   695  	for n := b.N; n > 0; n-- {
   696  		t += r.Float64()
   697  	}
   698  	Sink = uint64(t)
   699  }
   700  
   701  func BenchmarkExpFloat64(b *testing.B) {
   702  	r := testRand()
   703  	var t float64
   704  	for n := b.N; n > 0; n-- {
   705  		t += r.ExpFloat64()
   706  	}
   707  	Sink = uint64(t)
   708  }
   709  
   710  func BenchmarkNormFloat64(b *testing.B) {
   711  	r := testRand()
   712  	var t float64
   713  	for n := b.N; n > 0; n-- {
   714  		t += r.NormFloat64()
   715  	}
   716  	Sink = uint64(t)
   717  }
   718  
   719  func BenchmarkPerm3(b *testing.B) {
   720  	r := testRand()
   721  	var t int
   722  	for n := b.N; n > 0; n-- {
   723  		t += r.Perm(3)[0]
   724  	}
   725  	Sink = uint64(t)
   726  
   727  }
   728  
   729  func BenchmarkPerm30(b *testing.B) {
   730  	r := testRand()
   731  	var t int
   732  	for n := b.N; n > 0; n-- {
   733  		t += r.Perm(30)[0]
   734  	}
   735  	Sink = uint64(t)
   736  }
   737  
   738  func BenchmarkPerm30ViaShuffle(b *testing.B) {
   739  	r := testRand()
   740  	var t int
   741  	for n := b.N; n > 0; n-- {
   742  		p := make([]int, 30)
   743  		for i := range p {
   744  			p[i] = i
   745  		}
   746  		r.Shuffle(30, func(i, j int) { p[i], p[j] = p[j], p[i] })
   747  		t += p[0]
   748  	}
   749  	Sink = uint64(t)
   750  }
   751  
   752  // BenchmarkShuffleOverhead uses a minimal swap function
   753  // to measure just the shuffling overhead.
   754  func BenchmarkShuffleOverhead(b *testing.B) {
   755  	r := testRand()
   756  	for n := b.N; n > 0; n-- {
   757  		r.Shuffle(30, func(i, j int) {
   758  			if i < 0 || i >= 30 || j < 0 || j >= 30 {
   759  				b.Fatalf("bad swap(%d, %d)", i, j)
   760  			}
   761  		})
   762  	}
   763  }
   764  
   765  func BenchmarkConcurrent(b *testing.B) {
   766  	const goroutines = 4
   767  	var wg sync.WaitGroup
   768  	wg.Add(goroutines)
   769  	for i := 0; i < goroutines; i++ {
   770  		go func() {
   771  			defer wg.Done()
   772  			for n := b.N; n > 0; n-- {
   773  				Int64()
   774  			}
   775  		}()
   776  	}
   777  	wg.Wait()
   778  }
   779  
   780  func TestN(t *testing.T) {
   781  	for i := 0; i < 1000; i++ {
   782  		v := N(10)
   783  		if v < 0 || v >= 10 {
   784  			t.Fatalf("N(10) returned %d", v)
   785  		}
   786  	}
   787  }
   788  

View as plain text