Recently, for our company’s event, I planned to develop a lottery app that will randomly select the winners from the list. So, I immediately built a react application with random number generator code using Math.random() without any second thought and worked on functionality.
During demo of this application, my HR asked if the application can generate and pick numbers evenly across the full range of lottery tickets that were sold. I confidently said yes. However, when I actually generated winners (pseudo-random numbers) the results were not as expected. This called for an action to read and verify if the probability of generating any number within a range using any Pseudo Random Number Generators (PRNG)is following an uniform distribution.
JavaScript, being one of the most widely used programming languages, offers several utilities for generating random numbers. Two popular libraries, Math.random and random-js, are often used for this purpose. In this article, we will compare these two libraries and understand from statistical point of view.
The Math.random function is a built-in JavaScript method that generates a random floating-point number between 0 and 1. It is the simplest way to generate random numbers in JavaScript. However, it has certain limitations. random-js is a powerful random number generator library for JavaScript. It offers a wide range of features and capabilities that surpass those of Math.random.
// Code for Math.random
return Math.floor(Math.random() * 1000) + 1;
// Code for random-js
const engine = MersenneTwister19937.autoSeed();
const distribution = integer(1, 1000);
return distribution(engine);
Feature | Math.random | random-js |
---|---|---|
Seeding | Not possible | possible |
Distributions | Uniform only | Defaults to Uniform, but supports uniform, normal (Gaussian), exponential, and more |
Find about seeding and how to seed a random number
Small Sample vs Large Sample Size
For small sample size (in my case, no. of trails as I am always generating one number at a time) of generating 10 numbers from a population of 1000 (range), following is the distribution:


As you can see, Trail 1 which is represented in blue color, is similar to that of normal/negatively-skewed normal distribution (this can vary from session to session) while with each trial, the peak flattens. The following below is the distribution chart for same population (range of numbers) but generating 0.1 million random numbers. We can see that the distribution is close to uniform distribution, the expected result which is inferred from the Law of Large Numbers.


Tips to achieve improved randomness and uniformity
- Stratified Sampling is dividing the population into sub sections and samples are taken from each sub-section.
- Repeating the experiment in same session until we remove any biases and attain expected results
- Use of high quality RNGs likes cryptographic-strength algorithms e.g., Mersenne Twister or Xorshift or use
crypto.getRandomValues()
in JavaScript - Use libraries such as random-js that offer better control instead of Math.random to avoid modular biases
To summarize, achieving perfect uniformity in a small set of random numbers is challenging due to inherent randomness. Utilizing better algorithms, statistical tests, and enhancing the randomness sources can improve uniformity and reduce bias in random number generation.
And wait, though the probability of drawing a number by hand or generating through system is same, the perception of randomness might differ between handpicked numbers (which might be seen as more personal or “lucky”) and numbers generated by a computer algorithm. So, my HRs went with handpicking the winners of lottery.
Feature Image Source: https://www.ultimatesolver.com/en/random-lottery
Leave a Reply