Open up your dev tools’ (Mac: cmd + option + i / Windows: ctrl + shift + i), go to the Console, type `Math.random()`

, and hit return.

Bam. You get a random number.

I got 0.6199322557631561.

I’ve always wondered where on earth these numbers come from. And, more importantly, how can they possibly be random? After all, don’t computers just take in some input, swirl it around with some math, and then spit it back out? Seems like a pretty predictable process. So what happens when you want to generate a ‘random’ number? How does that even work and what’s happening behind the scenes?

#### For starters, it’s not really random

Surprise surprise, the answer is that `Math.random()`

doesn’t really generate a random number. Not exactly. It just does a really good job of simulating randomness.

Algorithmic random number generation can’t exactly be random, per se; which is why they’re more aptly called pseudo-random number generators (PRNGs). If you’re using math and formulae to create a sequence of numbers, random though they might seem, those numbers will eventually repeat and reveal a non-random pattern.

But some PRNGs are better than others. The quality of a PRNG depends on a number of factors, a very significant factor being something called its **period**; the number of iterations a PRNG goes through before it starts repeating itself. Not only does a PRNG with a long period *seem* more random to us humans but it’s also harder (i.e. more resource intensive) for a computer to crack / predict; a fact that has security implications even though no one should be using `Math.random()`

for encryption — but it happens anyways.

So now the question is: what PRNG does JavaScript use?

The answer: none.

#### It’s up to the browser

JavaScript doesn’t decide how `Math.random()`

gets implemented, your browser does. There’s no hard-coded PRNG algorithm that ships with JavaScript. Instead, the engineers who created your browser decided on an algorithm to use that conforms to the ECMAScript spec, which is as follows:

[Math.random] Returns a Number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. This function takes no arguments.

Each Math.random function created for distinct code Realms must produce a distinct sequence of values from successive calls.

Those are the instructions, it’s up to the browser to decide how to follow them. Until recently, different browsers used slightly different methods for accomplishing this. The algorithms that they used had sexy names like *Marsenne-Twister*, *Multiply With Carry*, or *Linear Congruential Generator. *Don’t worry, though, it’s not really important for you to understand what all of those things mean (although I’m completely impressed if you do).

The important thing to know about all this is that (1) browsers decide which algorithm they want to use to calculate `Math.random()`

and (2) in 2015 pretty much every browser (the major ones at least) ditched their old PRNG algorithms and now they all use the same one: called ** xorshift128+**.

As it turns out, xorshift128+ does a significantly better job at being pretend-random than the older algorithms; plus it’s extremely light weight and computationally fast. So it was adopted pretty much across the board, which speaks volumes to its effectiveness when you consider that there had previously been a lot of differing opinions on the matter.

But how exactly does it work?

While there are slight variations in the way that each browser implements the algorithm, we can look at a kind of “vanilla” version of it to understand how it works.

#### Some interesting math

First of all, I’m just going to show you the algorithm so that you can soak it all in (shown in C), then we’ll take a closer look:

uint64_tstate0 = 1;uint64_tstate1 = 2;

uint64_txorshift128plus() {

uint64_ts1 = state0;

uint64_ts0 = state1;

state0 = s0;

s1 ^= s1 << 23;

s1 ^= s1 >> 17;

s1 ^= s0;

s1 ^= s0 >> 26;

state1 = s1;

returnstate0 + state1;

}

If you’re like me (with a front-end background and no CS degree) you look at this and think “Ok, variable assignment, variable assignment, function… simple enough…” but then you come to `s1 ^= s1 << 23;`

and say “what the shit?”

These are **bitwise operators. **They manipulate data at the bit level (1’s and 0’s) and they form the heart and soul of the algorithm that we’re looking at. They’re also something that your average web developer rarely (if ever) has an occasion to work with. So in order to explain what this algorithm is doing, I’m going to quickly go over the three bitwise operators shown above and how they work.

The first operator, `<<`

, is called a left-shift. Here’s an example: `12 << 4`

. In this example, you’d take a binary representation of the number 12 and shift it to the left by 4 places; hence left-shift. Here’s how that works:

The inverse of this, called a right shift `>>`

, does the same thing but shifts right instead of left.

The second operator, `=^`

is the xor assignment operator. Xor (short for *exclusive or*) compares the binary representations of two numbers and outputs a 0 where corresponding bits match and outputs a 1 where corresponding bits are different. You can think of xor as ‘one *or* the other but *not both*’. Here’s a visualization of a random xor `53^18`

(xor without the assignment)

Now that you know what all the operators do, you can start to make sense of the xorshift algorithm above. That baffling bit that I mentioned earlier ( `s1 ^= s1 << 23;`

) is just left shifting s1 by 23 places and then xor-ing the result with s1, resulting in s1’s newly-assigned value. Or, in other words, it’s xor shifting.

So, to totally oversimplify things, the algorithm takes two seed values, switches them around, shuffles their bit values, puts their bit values through a logic gate, repeats this a few times, then adds them together and…

Bam. You get a ‘random’ number.

#### Conclusion (tl;dr)

To package everything up neatly, here’s an overview.

**Question:** how does JavaScript’s `Math.random()`

generate random numbers?

**Answer:**

- JS doesn’t do anything, it’s up to the browser
- As of 2015, most browsers use an algorithm called xorshift128+
- The numbers generated by xorshift128+ aren’t really random, the sequence just take a long time to repeat and they’re relatively evenly distributed over the expected range of values.

So, as it turns out, all we are really doing here is taking some input, swirling it around with some math, and spitting out a result. A completely predictable, nonrandom process. But one that feels random enough to us that it serves its purposes as our casual source of chaos in JavaScript.

*For anyone that’s interested, I have a JS implementation of xorshift128+ available on GitHub (linked below) that gives you a visualization of the algorithm’s ‘randomness’ and lets you play with **seed** and **shift** values. Thanks for reading!*