Skip to content

Generating Random Numbers

Vivek edited this page Sep 1, 2020 · 2 revisions

Using Math.random() can eat a lot of characters. If you need to call it more than once, you can do:

G=Math.random
// Then
G(),G(),G(),G()

(If you are calling G more than four times, you can spend 8 characters to remove those () parentheses, using Magna's valueOf trick.)

But we can also create some tiny pseudo-random number generators (PRNGs) which are close enough to random.

A good place to test and demonstrate PRNGs is to open Vuebeke's random challenge dweet.

You can experiment with different expressions by replacing the last line of that dweet. For example, try this poor example:

(i*i^60*t)/99%1
Click here for some other expressions you can try (hidden because SPOILERS!)
// If you only need one random number per frame (and you don't mind poor RNG in the early frames)
t**t%1
// Not very random, modifies t while iterating
t*++t%1
// Poor for low t and low i, breaks down after 111 seconds
i**t%M/M
// The rest of these can produce multiple random values in one frame
i*i*t/M%1
(t+i)**4%1
.5+S(i**t)/2
// These modify t instead of using i
(t=7*t**t%1)
(t=2*t*++t%1)

If you find a good expression, post a remix or a comment, to share it with us.

You might not always need a high quality PRNG. Sometimes the non-uniform patterns produced by an imperfect PRNG can be more visually interesting than pure noise would produce. Examples: 1

Vuebeke's random challenge is intended for numbers in the range 0 inclusive to 1 exclusive, like Math.random() produces. That is why many of the solutions use %1 to limit the range. However sometimes you might want numbers in a different range...

For numbers ranging -1 to +1

You can use sine or cosine S(i*t), C(i/t) but beware that these numbers are not evenly distributed. You will see numbers close to +1 or -1 more often than numbers close to 0.

For numbers ranging -Infinity to +Infinity

You can use tan, for example 0.2 * T(i*t) to get numbers ranging from -Infinity to +Infinity, but often close to zero, depending on the constant you divide or multiply by.

Xen likes to use tan to produce sudden movements, and also to spell the first letter of his name. Examples: ...

For whole numbers

Bitwise operators always produce whole numbers.

The exclusive or (XOR) of two numbers can produce unpredictable results, but with some temporary and broken patterns, due to bits being flipped. Thus it can be good for "glitchy" patterns.

In JavaScript the XOR operator can be applied using the hat symbol:

100 ^ 200 = 172
200 ^ 300 = 484
300 ^ 400 = 188

But note that XOR will become predictable around powers of two.

1 ^ 2 ^ 4 ^ 8 = 16 - 1

Example: You can try replacing the | with ^ in this dweet for some extra chaos.

Seeded Lehmer random number generator

This is a simple way to generate a reasonably random sequence

N = seed
N = N*B%A

A and B should be coprime. The best results are with A=65537 or 5337 and B=257 Other values work too, but only a few produce reasonably long periodicity (which seems to depend on A)

The useful thing about this technique is that it is a seeded PRNG, so you can get a deterministic, repeatable sequence. This is useful to draw things that look random, but only change slightly from frame to frame.

For example if you generate a 100 random numbers, but save the Nth one as the seed for the next frame, you get a progressive change every frame. With a low N this gives smooth transitions from frame to frame.