Pseudo-random Number Generator

From Second Life Wiki
Revision as of 11:02, 21 November 2007 by Xaviar Czervik (talk | contribs) (Changed the code slightly. (Or rather, a bit more than slightly...))
Jump to navigation Jump to search

See also: llFrand, llListRandomize, Seedable_PRNG

Seedable PRNG Based On Multiply/ Add/ Overflow

Here's a Pseudo-random Number Generator - I just made it up off the top of my head - so it has no mathematical research behind it to prove it's random... I've tested it for a while and it looks random to me, about the same as llFrand(). But what ever. Sue me. The main reason that I use it so that I can test scripts, and then when it blows up because of a math error, I can just run the script again an it will use the same numbers, in the same order.

I use this for determining a random channel for two (or more) objects to talk on. This allows the scripts to talk without users being able to intercept the messages - and even if they do - then the channel will change in a minute or two - so no harm done.


// IMPORTANT: Change the following numbers before using!
integer seed1 = 0x053FA20C;
integer seed2 = 0x3B1264D5;
integer seed1Mod = 0x71B5F252;
integer seed2Mod = 0x56A0E61D;

integer rand(integer spread) {
    	seed1 = (seed1 * seed1Mod + 0xB);
    	seed2 = (seed2 * seed2Mod + 0xB);
	integer answer = seed1 * seed2;
        seed2Mod = seed1Mod;
        seed1Mod = answer;
	return answer % spread;
}

Example code to test the randomness (Is that a word?) of the generator.

default {
	state_entry() {
		integer i = 0;
		integer min = 0x7FFFFFFF;
		integer max = -0x7FFFFFFF;
		integer total = 0;
		while (i < 100000000) {
			integer r = rand(0x7FFFFFFF);
			if (r < min) {
				min = r;
			}
			if (r > max) {
				max = r;
			}
			total += r;
			i++;
		}
		llOwnerSay("Min: " + (string)min);
		llOwnerSay("Max: " + (string)max);
		llOwnerSay("Average: " + (string)(total/100000000));

	}
}

Note: A pattern of digits like yyyymmddnn often works as a seed that changes often enough, e.g., test with 2007090103 == 2,007,090,103 as the 3rd try of the 1st day of the 9th month of the 2007th year, except you must take care to avoid confusing yourself with integers larger than the 2,147,483,647 limit of 32-bit signed arithmetic.

Note: Google Groups sci.math cites Knuth & Lewis suggesting the following linear congruential generator for 32-bit arithmetic processors. Someone skilled in the relevant mathematics should be able to prove that these choices of multiplier and addend provides results that feel more random. Someone skilled in Google might find yet more popular choices than these. People say the choose function returning the quotient rather than the remainder matters: try counting odd results and even results from the pseudorandom() routine to see why.

integer seed = 2007090103;

integer pseudorandom()
{
    seed = 1664525 * seed + 1013904223;
    return seed;
}

integer choose(integer count)
{
    integer nonnegative = 0x7fffFFFF;
    integer choice = pseudorandom() & nonnegative;
    return ((choice / (nonnegative / count)) % count);
}

default
{
    state_entry()
    {
        string line;
        integer index;

        line = "";
        for (index = 0; index < 9; ++index)
        {
           line += " " + (string) pseudorandom();
        }
        llOwnerSay(line);

        line = "";
        for (index = 0; index < 30; ++index)
        {
           line += " " + (string) (1 + choose(6));
        }
        llOwnerSay(line);

        llOwnerSay("OK");
    }
}