summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/rand/modulo_test.go
blob: da963c7b1922d4a69cc7298b6b5c774dbee73977 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 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.

// This file validates that the calculation in Uint64n corrects for
// possible bias.

package rand

import (
	"testing"
)

// modSource is used to probe the upper region of uint64 space. It
// generates values sequentially in [maxUint64-15,maxUint64]. With
// modEdge == 15 and maxUint64 == 1<<64-1 == 18446744073709551615,
// this means that Uint64n(10) will repeatedly probe the top range.
// We thus expect a bias to result unless the calculation in Uint64n
// gets the edge condition right. We test this by calling Uint64n 100
// times; the results should be perfectly evenly distributed across
// [0,10).
type modSource uint64

const modEdge = 15

func (m *modSource) Seed(uint64) {}

// Uint64 returns a non-pseudo-random 64-bit unsigned integer as a uint64.
func (m *modSource) Uint64() uint64 {
	if *m > modEdge {
		*m = 0
	}
	r := maxUint64 - *m
	*m++
	return uint64(r)
}

func TestUint64Modulo(t *testing.T) {
	var src modSource
	rng := New(&src)
	var result [10]uint64
	for i := 0; i < 100; i++ {
		result[rng.Uint64n(10)]++
	}
	for _, r := range result {
		if r != 10 {
			t.Fatal(result)
		}
	}
}