JavaScript - own random number generator (custom implementation)
In this article, we're going to have a look at how to write own random numbers generator that is based on LCG (Linear congruential generator) algorithm in JavaScript.
1. Introduction
In JavaScript, we can implement a custom random number generator by using LCG (Linear congruential generator) algorithm. LCG is one of the oldest and best-known pseudorandom number generator algorithm. We can adjust this implementation to work on int (32 bits) or long (64 bits) types - check parameters section. The algorithm works on and returns positive values.
The linear congruential generator is defined by the recurrence formula:
Where:
Xn+1
- new seed,Xn
- current seed (comes from previous calculations),m
- modulus (max possible returned integer value),a
- multiplier (integer value),c
- incrementer (integer value).
AND used m
, a
, and c
parameters should keep conditions:
0 < m
0 < a < m
0 <= c < m
0 <= X0 < m
2. Implementation
In this section, you can find custom implementation that uses BigInt
type to prevent against integer overflow. During double values calculations we use Number
type, ignoring least significant bits in integers that do not have impact during that calculations.
// ONLINE-RUNNER:browser;
function CustomRandom(seed) {
if (seed < 0) {
throw new Error('Seed value must be positive.');
}
const M = 2147483648n; // modulus (max possible integer value)
const A = 1103515245n; // multiplier
const C = 12345n; // incrementer
let R = BigInt(seed ?? Date.now()) % M;
this.nextInt = () => {
R = (R * A + C) % M;
return R;
};
this.nextDouble = () => {
const value = this.nextInt();
return Number(value) / Number(M);
};
}
// Usage example 1:
{
const random = new CustomRandom(3819201); // 3819201 is example initial seed
console.log(random.nextInt()); // 348328093
console.log(random.nextInt()); // 121065958
console.log(random.nextInt()); // 790325445
}
// Usage example 2 (values should always be different):
{
const random = new CustomRandom();
console.log(random.nextInt()); // 922892575
console.log(random.nextInt()); // 1117277734
console.log(random.nextInt()); // 2084933141
console.log(random.nextDouble()); // 0.6316955399847103
console.log(random.nextDouble()); // 0.5716405932659472
console.log(random.nextDouble()); // 0.3298228519641901
}
Note:
BigInt
type was introduced around 2018-2020 in the major web browsers.
3. LCG algorithm parameters
In this section, we can find parameters that are in common use by LCG.
From Wikipedia:
Source | modulusm | multipliera | incrementc |
---|---|---|---|
ZX81 | 65537 | 75 | 74 |
Numerical Recipes from the "quick and dirty generators" list, Chapter 7.1, Eq. 7.1.6 parameters from Knuth and H. W. Lewis | 4294967296 | 1664525 | 1013904223 |
Borland C/C++ | 4294967296 | 22695477 | 1 |
glibc (used by GCC) | 2147483648 | 1103515245 | 12345 |
ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++ C90, C99, C11: Suggestion in the ISO/IEC 9899, C17 | 2147483648 | 1103515245 | 12345 |
Borland Delphi, Virtual Pascal | 4294967296 | 134775813 | 1 |
Turbo Pascal | 4294967296 | 134775813 | 1 |
Microsoft Visual/Quick C/C++ | 4294967296 | 214013 | 2531011 |
Microsoft Visual Basic (6 and earlier) | 16777216 | 1140671485 | 12820163 |
RtlUniform from Native API | 2147483647 | 2147483629 | 2147483587 |
Apple CarbonLib, C++11's | 2147483647 | 16807 | 0 |
C++11's minstd_rand | 2147483647 | 48271 | 0 |
MMIX by Donald Knuth | 18446744073709551616 | 6364136223846793005 | 1442695040888963407 |
Newlib, Musl | 18446744073709551616 | 6364136223846793005 | 1 |
VMS's MTH$RANDOM, old versions of glibc | 4294967296 | 69069 | 1 |
Java's java.util.Random, POSIX [ln]rand48, glibc [ln]rand48[_r] | 281474976710656 | 25214903917 | 11 |
| 134456 | 8121 | 28411 |
POSIX [jm]rand48, glibc [mj]rand48[_r] | 281474976710656 | 25214903917 | 11 |
POSIX [de]rand48, glibc [de]rand48[_r] | 281474976710656 | 25214903917 | 11 |
cc65 | 8388608 | 65793 | 4282663 |
cc65 | 4294967296 | 16843009 | 826366247 |
cc65 | 4294967296 | 16843009 | 3014898611 |
Formerly common: RANDU | 2147483648 | 65539 | 0 |
Source: https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use