Pseudo-random Number Generator
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
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(). The main reason that I use it so that I can test scripts, and then when it blows up because of a math error or something I can just run the script again an it will use the same numbers, in the same order. It can also be used for two (or more) scripts to talk on a more-or-less channel. But what ever. Sue me.
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.
I recently compared this with llFrand() and it is on average 5% faster.
// IMPORTANT: Change the following number before using! integer seed = 0x61FA687C; integer rand() { seed = (integer)(seed * 0x71B5F252 + 0xD); return seed ^ 0x7FFFFFFF; }
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(); 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"); } }