Replicable RNG in Python and Javascript

John Salamon

2023-12-26

Xorshift

There’s a type of pseudorandom number generator (PRNG) called xorshift that’s super easy to implement and runs incredibly fast, as all you need is three xor operations and bitwise shifts. Well, you do also need an integer of fixed size. In C, the meat of a 32-bit xorshift might look like this:1

x ^= x << 7;
x ^= x >> 21;
x ^= x << 6;

Recently I wanted to generate some (predictable) random numbers for a web-based project that had Python running on the server, and Javascript running on the client. I really wanted both server and client to generate the same sequence of random numbers, so I implemented xorshift in both Javascript and Python. Only problem was, these languages handle integers very differently.

Python

In Python, the native integer type is int, which is actually an arbitrary precision type (not fixed size). The “fix” is pretty simple, just use a bitwise AND (&) to mask out any extra bits beyond 32, like so:

x ^= (x << 7) & 0xFFFFFFFF
x ^= x >> 21
x ^= (x << 6) & 0xFFFFFFFF

An alternative approach could be to use fixed-size integer types from numpy.

Javascript

In Javascript, the “number” type is 64-bit IEEE 754 floating point. It does support bitwise operations on numbers, by converting into a 32-bit integer. It’s a bit weird. I found James Darpinian’s blog post helpful. There is an unsigned right shift operator (>>>) that you can use to transform a number into what it would be as an unsigned int by shifting by zero, like so:

x ^= (x << 7) >>> 0;
x ^= x >>> 21;
x ^= (x << 6) >>> 0;

Another option would be to use the Javascript BigInt type, which does support bitwise operations. This is also what you’d have to use if you wanted an xorshift using more than 32 bits. With BigInt you could just mask out unwanted bits in the same way as the Python section above.

Conclusion

Xorshift is easy to implement on Javascript and Python, you just have to worry about how big your integers are.2