From c12a5464475c4b993ae5fc758fd943f2125e3653 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sat, 20 Nov 2021 15:20:42 -1000 Subject: [PATCH] Biased random generator --- gen/rand.go | 10 ++++++++++ test/rand_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 gen/rand.go create mode 100644 test/rand_test.go diff --git a/gen/rand.go b/gen/rand.go new file mode 100644 index 0000000..1f3c523 --- /dev/null +++ b/gen/rand.go @@ -0,0 +1,10 @@ +package gen + +import "math/rand" + +// Generate a random uint64 with an even distribution of bits.Len64() +func RandBiasedUint64() uint64 { + // The shift-right by up to 64 (shifting it to 0) makes up for randomness + // lost by setting the high bit. + return (rand.Uint64() | 0x8000000000000000) >> rand.Int31n(65) +} diff --git a/test/rand_test.go b/test/rand_test.go new file mode 100644 index 0000000..5821bab --- /dev/null +++ b/test/rand_test.go @@ -0,0 +1,33 @@ +package test + +import "math" +import "math/bits" +import "testing" + +import "github.com/firestuff/subcoding/gen" + +func TestRandBiasedUint64(t *testing.T) { + buckets := [65]uint64{} + + for i := 0; i < 1000000; i++ { + val := gen.RandBiasedUint64() + buckets[bits.Len64(val)]++ + } + + var max uint64 = 0 + var min uint64 = math.MaxUint64 + + for _, count := range buckets { + if count > max { + max = count + } + + if count < min { + min = count + } + } + + if max - min > max / 10 { + t.Fatalf("Variance greater than allowed: %d > %d (max=%d min=%d)", max - min, max / 10, max, min) + } +}