Mersenne Twister

July 19, 2026

cs math

Every time you call random.random() in Python, a generator called MT19937 runs, shuffles some bits around, and hands you back a number. MT19937 is an implementation of the Mersenne Twister, a pseudorandom number generator built in 1997 by Makoto Matsumoto and Takuji Nishimura.

It’s named after Mersenne primes, primes of the form 2p12^p - 1, because the generator’s cycle length before it repeats is exactly 21993712^{19937}-1, one such prime. It’s the engine behind Python’s random module, and most other languages use some version of it too.

Each of those numbers depends on a starting value called a seed. Most of the time nobody sets one directly though, Python just picks one for you automatically, by asking the operating system for some bytes of its own cryptographically secure randomness.

Python itself doesn’t generate this randomness, it just delegates to whatever secure source the OS provides: Linux uses a ChaCha20-based generator built into the kernel, macOS uses its own kernel CSPRNG, and Windows uses Microsoft’s CryptGenRandom.

That’s a whole topic on its own, so for this post we’ll skip it and just assume you called random.seed(42) yourself.

Setup

The Mersenne Twister can’t start from nothing. It needs a list of starting numbers to fill its internal memory before it can do anything.

Python’s internal memory holds 624 numbers, each 32 bits wide. Your seed needs to become a list of numbers that Python can use to fill that memory. This list is called the key.

For a small seed like 42, this is simple, the key is just that one number, wrapped in a list:

key=[42]\text{key} = [\,42\,]

For a much bigger seed, Python would split it into multiple 32-bit chunks instead, but the idea is the same. Either way, we now have a short list of numbers ready to feed into the actual algorithm. Getting this list wasn’t the Mersenne Twister itself, it’s just Python figuring out what to feed it.

Seeding

Before your actual key gets used, Python fills its 624-slot memory with a fixed, repeatable pattern. This step always starts from the exact same number, 19650218, no matter what your seed is. Think of it as priming the pump before pouring in your specific ingredients.

The rule for filling each slot from the one before it is:

mti=f(mti1(mti130))+i\text{mt}_i = f \cdot \left(\text{mt}_{i-1} \oplus (\text{mt}_{i-1} \gg 30)\right) + i

Here f=1812433253f = 1812433253 is just a fixed constant, and \oplus means XOR (flip bits where they differ).

Worked example. The first couple of slots, filled in by hand:

mt0=19650218=0x012bd6aa\text{mt}_0 = \texttt{19650218} = \texttt{0x012bd6aa} mt1=(1812433253×(0x012bd6aa0x0)+1)mod232=0x82d2ab13\begin{aligned} \text{mt}_1 &= \Big(1812433253 \times \big(\texttt{0x012bd6aa} \oplus \texttt{0x0}\big) + 1\Big) \bmod 2^{32} \\ &= \texttt{0x82d2ab13} \end{aligned} mt2=(1812433253×(0x82d2ab130x2)+2)mod232=0x342096b7\begin{aligned} \text{mt}_2 &= \Big(1812433253 \times \big(\texttt{0x82d2ab13} \oplus \texttt{0x2}\big) + 2\Big) \bmod 2^{32} \\ &= \texttt{0x342096b7} \end{aligned}

This repeats for all 624 slots. Notice your seed hasn’t even been used yet, this part is always identical no matter what.

Mix seed

Now Python walks through the memory a second time, this time actually folding your key into each slot:

mti(mti((mti1(mti130))×1664525))+keyj+j\text{mt}_i \leftarrow \Big(\text{mt}_i \oplus \big((\text{mt}_{i-1} \oplus (\text{mt}_{i-1} \gg 30)) \times \texttt{1664525}\big)\Big) + \text{key}_j + j

Since our key only has one number in it (42), this step reuses that same number over and over, once for each of the 624 slots.

Worked example. The very first mixing step, updating slot 1:

mt0(mt030)=0x012bd6aa0x0=0x012bd6aa\text{mt}_0 \oplus (\text{mt}_0 \gg 30) = \texttt{0x012bd6aa} \oplus \texttt{0x0} = \texttt{0x012bd6aa} (0x012bd6aa×1664525)mod232=0x7d5ba2a2\big(\texttt{0x012bd6aa} \times \texttt{1664525}\big) \bmod 2^{32} = \texttt{0x7d5ba2a2} mt10x7d5ba2a2=0x82d2ab130x7d5ba2a2=0xff8909b1\text{mt}_1 \oplus \texttt{0x7d5ba2a2} = \texttt{0x82d2ab13} \oplus \texttt{0x7d5ba2a2} = \texttt{0xff8909b1} new mt1=0xff8909b1+42+0=0xff8909db\text{new mt}_1 = \texttt{0xff8909b1} + 42 + 0 = \texttt{0xff8909db}

This repeats across all 624 slots, followed by one more short cleanup pass with a different multiplier. After all of it finishes, three of the resulting numbers, the ones we’ll need in a moment, look like this:

state[0]=0x80000000state[1]=0xd473a4c0state[397]=0xf91ab7fd\begin{aligned} \text{state}[0] &= \texttt{0x80000000} \\ \quad \text{state}[1] &= \texttt{0xd473a4c0}\\ \quad \text{state}[397] &= \texttt{0xf91ab7fd} \end{aligned}

Twist

This next step is where the algorithm gets its name, and where its famously long, never-repeating cycle comes from. To generate a new number for a given slot, three of the current numbers get mixed together, following this recurrence:

xk+n:=xk+m((xkuxk+1l)A)x_{k+n} := x_{k+m} \oplus \Big( (x_k^{u} \mid x_{k+1}^{l})\, A \Big)

where xkux_k^u means the top bits of slot kk, xk+1lx_{k+1}^l means the bottom bits of the next slot, \mid glues them together, and AA is a fixed matrix (applied efficiently as a shift plus conditional XOR, shown below).

In plain terms:

  1. Take the top bit of the current slot, and the bottom 31 bits of the next slot over. Glue them together into one number, call it xx.
  2. Shift xx one bit to the right.
  3. If xx was an odd number, XOR in a fixed constant, 0x9908b0df\texttt{0x9908b0df}. This is the “twist.”
  4. XOR the result with a slot much further ahead, 397 slots over.

Whatever comes out replaces the original slot.

Worked example. Computing the new value for slot 0:

state[0] top bit=0x80000000state[1] bottom 31 bits=0xd473a4c0 & 0x7fffffff=0x5473a4c0\begin{aligned} \text{state}[0]\ \text{top bit} &= \texttt{0x80000000} \\ \text{state}[1]\ \text{bottom 31 bits} &= \texttt{0xd473a4c0}\ \&\ \texttt{0x7fffffff} \\ &= \texttt{0x5473a4c0} \\ \end{aligned} x=0x800000000x5473a4c0=0xd473a4c0x1=0x6a39d260x = \texttt{0x80000000} \mid \texttt{0x5473a4c0} = \texttt{0xd473a4c0} \\ x \gg 1 = \texttt{0x6a39d260}

Since xx ends in a 0, it’s even, so the twist constant is skipped this time.

new state[0]=0xf91ab7fd0x6a39d260=0x9323659d\text{new state}[0] = \texttt{0xf91ab7fd} \oplus \texttt{0x6a39d260} = \texttt{0x9323659d}

That new number, 0x9323659d, isn’t the final output yet, it still needs one more pass.

Temper

The twisted number still has subtle bit patterns in it, so Python runs it through one more fixed sequence of shifts and XORs, called tempering. This is the very last thing the Mersenne Twister does before handing a number back:

y=x(x11)y=y((y7) & 0x9d2c5680)y=y((y15) & 0xefc60000)z=y(y18)\begin{aligned} y &= x \oplus (x \gg 11) \\ y &= y \oplus \big((y \ll 7)\ \&\ \texttt{0x9d2c5680}\big) \\ y &= y \oplus \big((y \ll 15)\ \&\ \texttt{0xefc60000}\big) \\ z &= y \oplus (y \gg 18) \end{aligned}

Worked example. Running our twisted value through all four passes:

y=0x9323659d0x00012646c=0x933101f1y=0x933101f10x98005080=0x0b315171y=0x0b3151710xa8800000=0xa3b15171z=0xa3b151710x000028ec=0xa3b1799d\begin{aligned} y &= \texttt{0x9323659d} \oplus \texttt{0x00012646c} = \texttt{0x933101f1} \\ y &= \texttt{0x933101f1} \oplus \texttt{0x98005080} = \texttt{0x0b315171} \\ y &= \texttt{0x0b315171} \oplus \texttt{0xa8800000} = \texttt{0xa3b15171} \\ z &= \texttt{0xa3b15171} \oplus \texttt{0x000028ec} = \texttt{0xa3b1799d} \end{aligned}
raw output #1 = 0xa3b1799d = 2746317213

That’s a full number out of the Mersenne Twister, start to finish: seed the memory, twist a slot, temper the result. Repeating steps 1c and 1d for the next slot over gives a second number:

raw output #2 = 478163327

Output

Here’s the part that’s specific to Python, not to the Mersenne Twister. A Python float needs 53 bits of precision, but each number out of the twister is only 32 bits. So Python takes two of them and glues them together:

a=raw15(keep the top 27 bits)b=raw26(keep the top 26 bits)result=a×226+b253\begin{aligned} a &= \text{raw}_1 \gg 5 &&\text{(keep the top 27 bits)} \\ b &= \text{raw}_2 \gg 6 &&\text{(keep the top 26 bits)} \\ \text{result} &= \frac{a \times 2^{26} + b}{2^{53}} \end{aligned}

Worked example. Using our two raw numbers from above:

a=27463172135=85822412a = 2746317213 \gg 5 = 85822412 b=4781633276=7471302b = 478163327 \gg 6 = 7471302 result=85822412×67108864+74713029007199254740992=0.6394267984578837\text{result} = \frac{85822412 \times 67108864 + 7471302}{9007199254740992} = 0.6394267984578837

And checking against real Python, seeded identically:

>>> import random
>>> random.seed(42)
>>> random.random()
0.6394267984578837

In conclusion, random.random() gets a seed value, the Mersenne Twister turns it into a stream of 32-bit numbers, and Python glues pairs of them into the float you actually see.

Reference

Below is the twist-and-temper core as C code, matching everything above with the real MT19937 constants:

#define n 624
#define m 397
#define w 32
#define r 31
#define UMASK (0xffffffffUL << r)
#define LMASK (0xffffffffUL >> (w-r))
#define a 0x9908b0dfUL
#define u 11
#define s 7
#define t 15
#define l 18
#define b 0x9d2c5680UL
#define c 0xefc60000UL

uint32_t random_uint32(mt_state* state)
{
    uint32_t* state_array = state->state_array;
    int k = state->state_index;

    int j = k - (n-1);
    if (j < 0) j += n;

    uint32_t x1 = state_array[k] & UMASK;
    uint32_t x2 = state_array[j] & LMASK;
    uint32_t x = x1 | x2;
    uint32_t xA = x >> 1;
    if (x & 1) xA ^= a;

    j = k - (n-m);
    if (j < 0) j += n;

    x = state_array[j] ^ xA;
    state_array[k++] = x;
    if (k >= n) k = 0;
    state->state_index = k;

    uint32_t y = x ^ (x >> u);
             y = y ^ ((y << s) & b);
             y = y ^ ((y << t) & c);
    uint32_t z = y ^ (y >> l);

    return z;
}

Every language’s random module is some version of this same loop, with its own choice of where the seed comes from, and its own formula for turning the raw output into whatever type you asked for.