How to Use a Seed to Generate Random Numbers in JavaScript
-
Use a Seed and
SFC32
to Generate a Random Number -
Use a Seed and
Mulberry32
to Generate a Random Number -
Use a Seed and
Xoshiro128**
to Generate a Random Number -
Use a Seed and
JSF
to Generate a Random Number -
Use
seedrandom.js
to Generate a Random Number
This article tackles how to use a seed to generate random numbers from PRNGs. Meanwhile, it’s a best practice to ensure that the seed for the PRNGs has high entropy.
Therefore, we’ll use a hashing function to generate the seed. Afterward, we pass the seed to the PRNG.
Use a Seed and SFC32
to Generate a Random Number
SFC32
or Simple Fast Counter is a fast PRNG from PractRand
(mostly in C), and it has an implementation in JavaScript with a 128-bit state, and it’s very fast. SFC32
requires at least a single seed to generate the random number.
We’ll generate this seed using the hashing function, a JavaScript implementation of MurmurHash3, which requires an initial string to generate the seed. As a result, we pass in a string.
In the following code, we generate the seed and pass it to SFC32
that returns the random number.
Code:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function SimpleFastCounter32(seed_1, seed_2, seed_3, seed_4) {
return () => {
seed_1 >>>= 0;
seed_2 >>>= 0;
seed_3 >>>= 0;
seed_4 >>>= 0;
let cast32 = (seed_1 + seed_2) | 0;
seed_1 = seed_2 ^ seed_2 >>> 9;
seed_2 = seed_3 + (seed_3 << 3) | 0;
seed_3 = (seed_3 << 21 | seed_3 >>> 11);
seed_4 = seed_4 + 1 | 0;
cast32 = cast32 + seed_4 | 0;
seed_3 = seed_3 + cast32 | 0;
return (cast32 >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = SimpleFastCounter32(generate_seed(), generate_seed());
console.log(random_number());
console.log(random_number());
Output:
0.837073584087193
0.3599331611767411
Use a Seed and Mulberry32
to Generate a Random Number
Mulberry32
is also a PRNG, though simpler in code structure than SFC32
. Contrary to SFC32
, which requires at least a seed.
We’ll use MurmurHash3 to generate the seed using a string. In the following example, we generate five random numbers using a for loop and Mulberry32
.
Code:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function Mulberry32(string) {
return () => {
let for_bit32_mul = string += 0x6D2B79F5;
let cast32_one = for_bit32_mul ^ for_bit32_mul >>> 15;
let cast32_two = for_bit32_mul | 1;
for_bit32_mul = Math.imul(cast32_one, cast32_two);
for_bit32_mul ^= for_bit32_mul +
Math.imul(for_bit32_mul ^ for_bit32_mul >>> 7, for_bit32_mul | 61);
return ((for_bit32_mul ^ for_bit32_mul >>> 14) >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = Mulberry32(generate_seed());
for (let i = 0; i < 5; i++) {
console.log(random_number());
}
Output:
0.13532060221768916
0.8630009586922824
0.53870237339288
0.5237146227154881
0.8748106376733631
Use a Seed and Xoshiro128**
to Generate a Random Number
Professor Vagna and Blackman developed the Xoshiro128**
generator. The xorshift128
is a family of the Xorshift
PRNGs, and it’s the fastest PRNG.
Like SFC32
, Xoshiro128**
can take at least a seed before producing the random number. In the following snippet, we’ve created the required seed with MurmiurHash3.
Code:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function Xoshiro128_twostar(seed_1, seed_2, seed_3, seed_4) {
return () => {
let t = seed_2 << 9, y = seed_1 * 5;
y = (y << 7 | y >>> 25) * 9;
seed_3 ^= seed_1;
seed_4 ^= seed_2;
seed_2 ^= seed_3;
seed_1 ^= seed_4;
seed_3 ^= t;
seed_4 = seed_4 << 11 | seed_4 >>> 21;
return (y >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = Xoshiro128_twostar(generate_seed(), generate_seed());
console.log(random_number());
Output:
0.6150987280998379
Use a Seed and JSF
to Generate a Random Number
Bob Jenkins created Jenkins Small Fast (JSF) generator, a fast generator. Though, it’s not fast when compared to SFC32
.
When you observe the code of JSF
, you’ll see similarities to SFC32
. JSF
can take more than a seed before producing a random number.
We generate ten random numbers with a seed and JSF
in the next code.
Code:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function JenkinsSimpleFast32(seed_1, seed_2, seed_3, seed_4) {
return () => {
seed_1 |= 0;
seed_2 |= 0;
seed_3 |= 0;
seed_4 |= 0;
let t = seed_1 - (seed_2 << 27 | seed_2 >>> 5) | 0;
seed_1 = seed_2 ^ (seed_3 << 17 | seed_3 >>> 15);
seed_2 = seed_3 + seed_4 | 0;
seed_3 = seed_4 + t | 0;
seed_4 = seed_1 + t | 0;
return (seed_4 >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = JenkinsSimpleFast32(generate_seed(), generate_seed());
for (let i = 0; i < 10; i++) {
console.log(random_number());
}
Output:
0.513338076416403
0.4737987464759499
0.5743723993655294
0.4811882192734629
0.07753282226622105
0.11416710214689374
0.1270705321803689
0.15759771666489542
0.16906401910819113
0.6846413582097739
Use seedrandom.js
to Generate a Random Number
seedrandom.js
is a library by David Bau designed for seeded Random Number Generator (RNG), and it’s available on NPM and CDNJS. For this article, we’ll use CDNJS.
Keep the following in mind when using Seedrandom.js
.
- You initialize
seedrandom
usingnew Math.seedrandom('seed key')
. - You can use the
quick()
function ofSeedrandom
to generate 32-bit of randomness. - The
int32()
function of Seedrandom.js returns a 32-bit signed integer. - Calling
seedrandom
with no arguments causes the creation of an auto-seeded ARC4-based PRNG. The auto-seeding uses some values like the accumulated local entropy. Seedrandom
can take an object as a second argument. This object is{entropy: true}
, and the result is unpredictable.- Calling
Math.seedrandom
without thenew
keyword replaces the defaultMath.random()
. The replacement isnew Math.seedrandom()
.
In this example, we’ve imported seedrandom.js
from CDNJS. Afterward, we use it to generate a random number using a seed.
Code:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('Johnson');
console.log(generate_random_number());
</script>
</body>
Output:
0.08103389758898699
You can mix your seed with the accumulated entropy. You’ll need to pass {entropy: true}
as the second argument of seedrandom
.
Code:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('Antananarivo', { entropy: true });
for (let i = 0; i < 5; i++) {
console.log(generate_random_number());
}
</script>
</body>
Output:
0.8478730572111559
0.963664252064149
0.6002684820777331
0.4026776455839767
0.7579996916288508
In addition, quick()
and int32()
will return random 32-bit random numbers. The former will return a float, while the latter returns a signed integer.
Code:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('DavidBau');
console.log("With quick():", generate_random_number.quick());
console.log("With int32():", generate_random_number.int32());
</script>
</body>
Output:
With quick(): 0.249648863915354
With int32(): -550219731
Habdul Hazeez is a technical writer with amazing research skills. He can connect the dots, and make sense of data that are scattered across different media.
LinkedIn