Understanding Math.random()

Mogwai™
life of mogwai.
Published in
3 min readAug 1, 2020

It’s incredible the number of times you’ll have to use Math.random() (out of all the Math methods that ship out-of-the-box with JavaScript).

If you’re a creative coder, you’ll need it to make generative art (even though many of the tools of creative coding ship their own flavor of the trusty Math.random()). As a result, it’s probably a great idea to reason about how Math.random() works.

At its very base, Math.random() is designed to do only one thing: generate a number between 0 and 1. I like to think of it as a white noise machine, generating white and black pixels to fill a whole screen. That analogy is powerful when you consider that white noise machines go into the creation of mosaics and even procedurally generated clouds, among other things.

In other words, Math.random() is deceptively simple:

0≤ n <1
//What Math.random generates

Math.random() generates a number between zero and one, but never (or rarely ever) generates one itself.

Extending Math.random()

If we think of 0≤n<1 as an algorithm for the procedural generation of random floating digits, we can then generate numbers not limited to 0 and one. We only need to reduce the skeleton of our desired range to the base format.

Say you want to generate a number between 5 and 15. This is the mental sequence you’ll follow:

  1. I need a number between 5 and 15.
  2. This can be represented mathematically as 5≤n<16 (can you guess why we write 16 and not 15?)
  3. But Math.random() can only think in 1s and 0s. So how to get things in agreement?
  4. First subtract five from every part of that mathematical model of computation.
  5. That gives us 5–5≤n-5<16–5…
  6. …which is 0≤n-5<11
  7. Okay. So we have a zero on one end. But we need a 1, not an 11, on the other end!
  8. Oh, I know! Let’s divide everything by 11!
  9. 0/11≤(n-5)/11<11/11
  10. That’s 0≤(n-5)/11<1
  11. Yay!
  12. But we aren’t done :(
  13. You see, (n-5)/11 is r. That is, the random number Math.random() will generate. What we want to get it the factor we’ll multiply r by to get numbers within the range we want (in this case, 5–15). To do this, we have to find n .
  14. r = (n-5)/11
  15. Multiply both sides by 11
  16. n-5 = r*11
  17. Add five to both sides
  18. n = (r*11) + 5

Let’s take this for a spin, shall we? Let’s write a function called fiveToFifteen.

And it works!

But what if you wanted to change the number from five and fifteen to, say 8 and 19? Will you have to do that 18-step reasoning we did earlier?

Mercifully not. Instead of thinking in pure numbers (5 and 15), we can think in terms of min and max.

0 is min, 1 is max.

So we can start with this basic idea instead:

min ≤n<max

If we go through the 18 steps again, we have something like this at step 9:

min-min≤n-min<max-min, which gives us 0≤n-min<max-min

Divide through by (max-min), and we get:

0/(max-min)≤n-min/(max-min)<(max-min)/(max-min)

0≤n-min/(max-min)<1

Aha.

We can then run r = (n-min)/max-min

Multiply both sides by (max-min), and we get

r * (max-min) = n-min

Add min

r * (max-min) + min = n

we can then rewrite our function to adapt to any random number generation need like this:

Thanks to Scrimba’s math for frontend developers for helping me understand this, and I hope it is a useful mental model for you as well!

--

--

Mogwai™
life of mogwai.

Storyteller. Product Growth Boy. Spawn of JavaScript.