golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/rand/modulo_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  // This file validates that the calculation in Uint64n corrects for
     6  // possible bias.
     7  
     8  package rand
     9  
    10  import (
    11  	"testing"
    12  )
    13  
    14  // modSource is used to probe the upper region of uint64 space. It
    15  // generates values sequentially in [maxUint64-15,maxUint64]. With
    16  // modEdge == 15 and maxUint64 == 1<<64-1 == 18446744073709551615,
    17  // this means that Uint64n(10) will repeatedly probe the top range.
    18  // We thus expect a bias to result unless the calculation in Uint64n
    19  // gets the edge condition right. We test this by calling Uint64n 100
    20  // times; the results should be perfectly evenly distributed across
    21  // [0,10).
    22  type modSource uint64
    23  
    24  const modEdge = 15
    25  
    26  func (m *modSource) Seed(uint64) {}
    27  
    28  // Uint64 returns a non-pseudo-random 64-bit unsigned integer as a uint64.
    29  func (m *modSource) Uint64() uint64 {
    30  	if *m > modEdge {
    31  		*m = 0
    32  	}
    33  	r := maxUint64 - *m
    34  	*m++
    35  	return uint64(r)
    36  }
    37  
    38  func TestUint64Modulo(t *testing.T) {
    39  	var src modSource
    40  	rng := New(&src)
    41  	var result [10]uint64
    42  	for i := 0; i < 100; i++ {
    43  		result[rng.Uint64n(10)]++
    44  	}
    45  	for _, r := range result {
    46  		if r != 10 {
    47  			t.Fatal(result)
    48  		}
    49  	}
    50  }