I have all kinds of resources that rely on javascript random numbers. However, I\'ve been seeing a lot of problems where random isn\'t so random because of the way I\'m gene
While looking for an alternative for Math.random I stumbled on this question.
While those are valid answers, the solution that worked for me was simply using Math.random twice.
And use a modulus on the decimals of the float.
Basically to increase the randomness.
Maybe it might be usefull for some who were guided by google to this question.
Here's a snippet with the function, and one that runs it a million times.
function rand(min, max){
return (Math.floor(Math.pow(10,14)*Math.random()*Math.random())%(max-min+1))+min;
}
// testing rand
function rollRands(min, max, rolls) {
let roll = 0, n = 0;
let counts = {};
for(let i = min; i <= max; i++){
counts[i]=0
}
while (roll < rolls){
roll++;
counts[rand(min,max)]++;
}
return counts;
}
console.log(rollRands(36, 42, 1000000));
I agree with Phil H that humans are so good at finding patterns that they often think they see patterns even in "perfectly random" sequences of numbers (clustering illusion, apophenia, gambler's fallacy, etc).
Plots of true random positions generally have lots of clumps and points that "coincidentally" fall very close together, which looks pretty suspicious.
Artists often take completely randomly generated patterns and "nudge" them to make them appear "more random", even though that careful nudging actually makes the pattern less random (a), (b), (c), (d), etc.
Alternatively, a low-discrepancy sequence sometimes "looks better" than a true random sequence and is much faster to generate.
There are many "random number generators" across a whole spectrum from "extremely fast" to "relatively slow" and from "easy for even a human to see patterns" to "unlikely that unassisted humans could ever see any patterns" to "cryptographically secure and, after seeded with adequate amounts of entropy, as far as we can tell, indistinguishable from random to any attacker using less than all the energy produced by humanity for a month."
Non-cryptographic-strength random number generators that still give excellent output (unlikely that unassisted humans could ever see any patterns) include the Mersenne twister, multiply-with-carry, Lagged Fibonacci generator, Well equidistributed long-period linear, Xorshift, etc.
I hear that Cryptocat and other JavaScript applications use the convenient window.crypto.getRandomValues()
or window.msCrypto.getRandomValues()
or SubtleCrypto.generateKey()
functions that are designed to generate cryptographic random numbers. Unfortunately, that function is not available in IE 11 and below.
Since web browsers use random numbers all the time (for every "https://" page they fetch), it's quite likely that these functions (where available) may run faster than most random number generators written in JavaScript -- even non-cryptographic algorithms.
One way to generate true random numbers in JavaScript is to capture mouse events and add them into a pool of entropy, keeping track of some (hopefully conservative) estimate of the entropy added. Once the pool is "full" (estimates indicate that at least 128 bits of entropy have been added), use some cryptographically secure random number generator to generate random numbers from the pool -- typically by using a one-way hash so that a sequence of a few thousand output numbers are not enough to deduce the state of the entropy pool and hence predict the next output number.
One implementation: http://lightsecond.com/passphrase.html
Assuming you're not just seeing patterns where there aren't any, try a Mersenee Twister (Wikipedia article here). There are various implementations like this one on github.
Similar SO question:
Seedable JavaScript random number generator
If you want something closer to truly random, then consider using the random.org API to get truly random numbers, although I would suggest only using that to seed, not for every number, as you need to abide by their usage limits.
Rando.js is cryptographically secure. It's basically window.crypto.getRandomValues() that uses window.msCrypto.getRandomValues() as a failsafe and Math.random() as a last resort failsafe, but it's easier to implement and use. Here's a basic cryptographically secure random [0, 1) number:
console.log(rando());
<script src="https://randojs.com/2.0.0.js"></script>
Nice and easy. If that's all you wanted, you're good to go. If you want it to do more for you, it's also capable of all this:
console.log(rando(5)); //an integer between 0 and 5 (could be 0 or 5));
console.log(rando(5, 10)); //a random integer between 5 and 10 (could be 5 or 10));
console.log(rando(5, "float")); //a floating-point number between 0 and 5 (could be exactly 0, but never exactly 5));
console.log(rando(5, 10, "float")); //a floating-point number between 5 and 10 (could be exactly 5, but never exactly 10));
console.log(rando(true, false)); //either true or false
console.log(rando(["a", "b"])); //{index:..., value:...} object representing a value of the provided array OR false if array is empty
console.log(rando({a: 1, b: 2})); //{key:..., value:...} object representing a property of the provided object OR false if object has no properties
console.log(rando("Gee willikers!")); //a character from the provided string OR false if the string is empty. Reoccurring characters will naturally form a more likely return value
console.log(rando(null)); //ANY invalid arguments return false
//Prevent repetitions by grabbing a sequence and looping through it
console.log(randoSequence(5)); //an array of integers from 0 through 5 in random order
console.log(randoSequence(5, 10)); //an array of integers from 5 through 10 in random order
console.log(randoSequence(["a", "b"])); //an array of {index:..., value:...} objects representing the values of the provided array in random order
console.log(randoSequence({a: 1, b: 2})); //an array of {key:..., value:...} objects representing the properties of the provided object in random order
console.log(randoSequence("Good gravy!")); //an array of the characters of the provided string in random order
console.log(randoSequence(null)); //ANY invalid arguments return false
<script src="https://randojs.com/2.0.0.js"></script>
It supports working with jQuery elements too, but I left that out of this demo so I wouldn't have to source in jQuery. If you need that, just check it out on the GitHub or website.
There seems to be slight confusion here between two things that are very different:
Apologies to those who know this already, but the two are worlds apart. Pseudorandom numbers appear random and may even pass sophisticated tests of randomness, but they are deterministic. Because of this, they are useless for cryptography, and may have other flaws where true randomness is required.
True randomness is non-deterministic, and thus unpredictable. A key concept here is one of entropy, or the amount of non-redundant information contained. There is a limited number of ways of obtaining truly random data. 'Good' sources are:
Other 'sources of randomness' like mouse movements and internal variations in computer disk timing, etc. are often harnessed, but may be less-than-perfect. Generally, I've found that it's easier to access the entropy pool on a Linux system than under Windows, but this may just be personal bias.
If you just want random-appearing numbers, then yes, using the Mersenne twister is a viable option. It jumps around like crazy. If you're generating random numbers to use as e.g. version 4 UUIDs, then you need to be more careful. You can't simply 'add entropy' if it's not there, even by applying deterministic cryptographic functions.
If you intend to use your randomness for cryptography, you should also be intensely aware of the many ways your source of randomness can become compromised. For example, if you're using an Internet-based 'source of randomness', who can tap into this?
you can generate a pool of random numbers just by requesting some data asynchronously because performance.now() gives you time precision up to microseconds. Then use the response time as a salt in a randomising algorithm,
var randomNumbers = [];
for(var i = 0; i < 10; i++) {
setTimeout(function () {
var timeStart = performance.now();
xhttp = new XMLHttpRequest();
xhttp.open('GET', 'https://cdn.polyfill.io/v2/polyfill.min.js?rand=' + Math.random(), true);
xhttp.onload = function () {
var timeEnd = performance.now() - timeStart;
var rNumber = parseInt(timeEnd.toString().replace('.', ''));
randomNumbers.push(rNumber)
};
xhttp.send();
}, i * 10);
}
There are many factors that will affect this time:
It's not good to generate millions of numbers this way but a few. Maybe concatenate a few results to get a good, long random number.