As already indicated in the comments, the naming of the functions is weird. Both waver
and until
are not well chosen.
The functions you've provided look very much as the example in the JavaScript documentation for the function Math.random():
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive
}
However, you can see that the + 1
you did isn't there, that's if the max
value is inclusive. However, you've specified "until" as indicator, which would mean that the intent is to be exclusive.
The problem with using floating point values and operations is that they are always limited by a specific amount of precision. That in turn will mean that the function is ever so slightly biased. Usually this amount of bias can be safely ignored, but now always.
Instead it may be a better idea to use and rejection sampling using integers. Additionally I'd rather use a cryptographically secure random number generator that provides many security properties over Random
.
function getRandomInt(max) {
if (max <= 0 || !Number.isInteger(max)) {
throw new Error("The max value should be a positive integer.");
}
const bitLength = Math.ceil(Math.log2(max));
const byteLength = Math.ceil(bitLength / 8);
const rejectionLimit = Math.pow(2, bitLength) - max;
const buffer = new Uint8Array(byteLength);
while (true) {
crypto.getRandomValues(buffer);
let randomValue = 0;
for (let i = 0; i < byteLength; ++i) {
randomValue |= (buffer[i] << (8 * i));
}
// Zero out the bits that are out of range, based on bitLength
randomValue &= (Math.pow(2, bitLength) - 1);
// Reject the sample if it's larger than the max value.
if (randomValue >= rejectionLimit) {
continue;
}
return randomValue % max;
}
}
To use this with a minimum value as well:
function getRandomIntInRange(min, max) {
if (!Number.isInteger(min) || !Number.isInteger(max) || max <= min) {
throw new Error("Both min and max should be integers with max > min.");
}
const range = max - min;
const randomInt = getRandomInt(range);
return randomInt + min;
}
Beware that this is untested code. I'm pretty sure it works, but please test it before actual deployment.
waver.until(10)
would then return 10 possible values, instead of 11, but as I said, user275698 might have intended to return 11 possible values. \$\endgroup\$