Skip to content

uniform-int (and likely other distributions) are not as uniform as possible #45

@bigfarts

Description

@bigfarts

uniform-int currently functions by stretching the output range of the RNG into the desired range. However, this is not strictly correct as it depends on the output size of the RNG. For instance, with a small-scale example, if the RNG only outputs 16 bits and we're generating a number from 0 to 5:

>>> collections.Counter(i * 6 // 0xffff for i in range(0xffff))
Counter({0: 10923, 2: 10923, 4: 10923, 1: 10922, 3: 10922, 5: 10922})

We can run a simulation to see the effect of this as well:

const random = require("random")

const hist = new Map();

for (let i = 0; i < 20000000; i++) {
    const n = random.int(0, 5);
    hist.set(n, (hist.get(n) || 0) + 1);
}

and we get:

Map(6) {
  4 => 3334526,
  5 => 3333539,
  3 => 3334684,
  1 => 3331604,
  0 => 3333306,
  2 => 3332341
}

In order to get a truly uniform distribution, the generator needs to instead:

  • operate by generating bits with a uniform distribution (it's likely that Math.random will at least be uniform over 64 bits, so it's possible to generate 64 bits at a time).
  • generate enough bits to hold the max value
  • if the generated number is > max value, discard and try again

https://github.com/python/cpython/blob/8a0d9a6bb77a72cd8b9ece01b7c1163fff28029a/Lib/random.py#L235-L243 has an example of how it works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions