This thread is for code and information on random number generation. For most uses, Pixelblaze’s built-in random() function is the right solution, but if you need something a little different, this is the place to start looking!
random(x) of course, generates a random number between 0 and x, exclusive, with a uniform distribution. I don’t know its implementation details. If it’s seeded rather than hardware, the seed is not available to patterns. If you call it multiple times, you’ll get a different sequence of random numbers every time.
So the first set of alternative methods I’ll give are seeded psuedo-random generators (PRNGs) that, for a given seed, always return the same sequence of numbers. This sort of generator is extremely useful for making repeatable procedural and generative graphics. The random procedural dungeons and worlds in many games are made this way, starting with a single number as a seed.
Here are a couple of algorithms to get things rolling :
xorshift - very lightweight and fast. Popular for games and small computers. This example is taken from @wizard’s “static random colors” library pattern.
xorshift Source Code
// 16 bit xorshift from
// http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html
var xs
function xorshift() {
xs ^= xs << 7
xs ^= xs >> 9
xs ^= xs << 8
return xs
}
// return a pseudorandom value between 0 and 1
function pseudorandomFraction() {
return xorshift() / 100 % 1
}
Wolfram Rule 30 - This is kind of overkill, but if you need a stream of pseudo-random bits as well as random numbers of user specified word length, it’s is worth considering. It uses the chaotic central column of a cellular automaton as its random bitstream source. The pattern is one I did as part of @scruffynerf’s first tutorial task series.
Rule 30 Flasher in forum thread
Code for Task #1 - Random Random Roger Roger! - #8 by zranger1
All of the algorithms above generate random numbers in a uniform distribution. In most cases, that’s exactly what you want. But just in case… here’s code I cooked up a while ago that shows two different methods for generating normally distributed random numbers – numbers near the center of the range will come up frequently, and the extremes less frequently.
I was going to use this as part of a particle system to procedurally generate grass-like plants, which I haven’t yet got 'round to. (but I did get to dust off my 90’s paper copy of Knuth’s “The Art of Computer Programming”, which is always fun!)
RNG with Normal Distribution Source Code
var frameTime = 888;
export var speed = 60;
export var method = 0; // 0 - Box-Muller, 1 - Marsaglia
export var val = 0;
export function sliderSpeed(v) {
speed = 150 * (1-v)
}
export function sliderMethod(v) {
method = (v > 0.5);
}
export function beforeRender(delta) {
frameTime += delta;
t1 = time(.1)
if (frameTime > speed) {
if (method) {
val = gaussianRandomMarsaglia();
} else {
val = gaussianRandomBoxMuller();
}
frameTime = 0;
}
}
// display random pixels so you can see the distribution. It should
// have a marked central tendency -- extremes should light up infrequently.
export function render(index) {
var h = t1 + index/pixelCount
var s = 1
var v = index == floor(val * pixelCount);
hsv(h, s, v)
}
// largest number our regular random() function should generate
// used by both functions.
var MAX_RANDOM = 32763;
// Box-Mueller transform method for generating normally distributed
// random numbers in the range 0..1.
// https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
var bmU,bmV;
var bmPhase = 0;
function gaussianRandomBoxMuller() {
var z;
if(!bmPhase) {
bmU = (random(MAX_RANDOM) + 1) / (MAX_RANDOM + 2);
bmV = random(MAX_RANDOM) / (MAX_RANDOM + 1);
z = sqrt(-2 * log(bmU)) * sin(2 * PI * bmV);
} else
z = sqrt(-2 * log(bmU)) * cos(2 * PI * bmV);
bmPhase = !bmPhase;
// scale to proper range -- the algorithm converges on 4.4 - -4.4
return 0.5+(z/8.8);
}
// Marsaglia (Knuth) method for generating normally distributed
// random numbers from 0..1.
// Algorithm from Knuth's The Art of Computer Programming, vol 2
// sec 3.4.1, p 118. Attributed to G. Marsaglia.
var v1, v2,ks;
var kPhase = 0;
function gaussianRandomMarsaglia() {
var x,u1,u2;
if(!kPhase) {
while (1) {
u1 = random(MAX_RANDOM) / MAX_RANDOM;
u2 = random(MAX_RANDOM) / MAX_RANDOM;
v1 = 2 * u1 - 1;
v2 = 2 * u2 - 1;
ks = v1 * v1 + v2 * v2;
if (ks < 1 && ks > 0) break;
}
x = v1 * sqrt(-2 * log(ks) / ks);
} else
x = v2 * sqrt(-2 * log(ks) / ks);
kPhase = !kPhase;
// scale to proper range -- the algorithm converges on 4.0 - -4/0
return 0.5+(x/8);
}