This is not a uniform distribution:
const randIntRange = (i, j, engine = defaultEngine) => {
const min = Math.ceil(i)
const max = Math.floor(j)
return Math.floor(engine() * (max - min + 1)) + min
}
If you assume engine() outputs, say, 64 bits of entropy, any number range that is not an even factor of 2^64 will exhibit intermittent bias where the numbers are rounded.The only correct way to do this is to do rejection sampling: generate an integer x with log2(max - min) bits and if x >= max - min retry until you do:
function randBelow(n) {
const nbits = Math.ceil(Math.log2(n));
while (true) {
const x = getRandBits(nbits);
if (x < n) { return x; }
}
}
function randIntHalfOpenRange(min, max) {
return min + randBelow(max - min);
}
function randIntRange(min, max) {
return randIntHalfOpenRange(min, max + 1);
}
The primitive you want for building distributions on is not to generate a floating point number between 0.0 and 1.0, but to generate an integer of at most x bits.