← Download MyJS
MyJS block
random 1.0.0
Generates a random number between two limits.
- Exports
-
random - Works in
- Browser and Node.js
- Tags
- random
The code of version 1.0.0
/**
* @typedef RandomOptions
* @property {boolean} [returnInt=false]
* If `true`, returns a whole number: one of the integers from
* `includedLimit` (rounded toward `excludedLimit` if it isn't whole) up to
* but not including `excludedLimit`.
* @property {boolean} [useCrypto=false]
* If `true`, uses `crypto.getRandomValues()` instead of `Math.random()`, so
* the result can't be predicted.
*/
/**
* Generates a random number between two limits. `includedLimit` can be
* returned but `excludedLimit` never is. Either one can be the larger.
* @param {number} includedLimit
* One end of the range, which can be returned.
* @param {number} excludedLimit
* The other end of the range, which is never returned.
* @param {RandomOptions} [options]
* @returns {number}
* @throws {RangeError}
* If a limit isn't a finite number, or there's no number (or, with
* `returnInt`, no integer) that can be returned.
*
* @example <caption>Rolling a die</caption>
* random(1, 7, { returnInt: true });
* // → 1, 2, 3, 4, 5 or 6
*
* @example <caption>A decimal number</caption>
* random(0, 100);
* // → a number like 42.81637 (never 100)
*
* @example <caption>Limits in either order</caption>
* random(10, 0, { returnInt: true });
* // → 1 to 10: 10 can be returned but 0 can't
*
* @example <caption>Limits that aren't whole numbers</caption>
* random(0.5, 3.5, { returnInt: true });
* // → 1, 2 or 3
*
* @example <caption>Picking from a list</caption>
* const colors = ['red', 'green', 'blue'];
* colors[random(0, colors.length, { returnInt: true })];
* // → 'red', 'green' or 'blue'
*
* @example <caption>A code that can't be predicted</caption>
* random(100000, 1000000, { returnInt: true, useCrypto: true });
* // → a six-digit number like 583019
*/
function random(includedLimit, excludedLimit, options) {
const { returnInt = false, useCrypto = false } = options ?? {};
if (!Number.isFinite(includedLimit) || !Number.isFinite(excludedLimit)) {
throw new RangeError('Both limits must be finite numbers.');
}
const asc = includedLimit < excludedLimit;
let start = includedLimit;
let size = Math.abs(excludedLimit - includedLimit);
if (returnInt) {
// The first and the just-out-of-range integers, counting from includedLimit
start = asc ? Math.ceil(includedLimit) : Math.floor(includedLimit);
const end = asc ? Math.ceil(excludedLimit) : Math.floor(excludedLimit);
size = Math.abs(end - start);
}
if (!size) {
throw new RangeError(`There's no ${returnInt ? 'integer' : 'number'} from ${includedLimit} up to but not including ${excludedLimit}.`);
}
for (;;) {
let fraction;
if (useCrypto) {
// 32 bits from the first number and 21 from the second make a 53-bit
// integer, which divided by 2**53 gives [0, 1) like Math.random()
const uints = crypto.getRandomValues(new Uint32Array(2));
fraction = (uints[0] * 0x200000 + (uints[1] >>> 11)) / 0x20000000000000;
} else {
fraction = Math.random();
}
let offset = fraction * size;
if (returnInt) {
offset = Math.floor(offset);
}
const result = asc ? start + offset : start - offset;
// Rounding can land a float on excludedLimit, so pick again (very rare)
if (result !== excludedLimit) {
return result;
}
}
}
Versions
-
1.0.0 Oct 23, 2026
Initial