// *near* 50:50 chance of "Heads" vs. "Tails"
integer coin_toss()
{
if (llFrand(1.0) < 0.5) return TRUE;
return FALSE;
}
// Sometimes it is useful to get a random integer over a given range. This is
// a surprisingly tricky and emotive subject and has caused endless discussion
// on the scripting groups. The primary cause of probability errors when
// employing llFrand is to have a varying bin size on the edges of the range.
//
// As the bracket notation indicates, [0.0, mag), the function is inclusive of
// the 0.0 and exclusive of the entered value. Because an LSL floating point
// number is only a subset of real numbers and does not have infinite
// granularity, this schema will work for any float greater than float
// t = 1.175494351e-38; at which value the function will return only zero. At a
// float beyond this, a math error occurs.
// Random integer generator:
// Contributed by Mephistopheles Thalheimer,
// original function posted by Hg Beeks
// Returns a pseudo-random integer in the range of min to max inclusive.
// Rationale:
// Expands the range by 1.0 to ensure equal bin spacing on ends relative to
// the middle of the range and then uses an integer cast to round towards
// zero.
// Caveats:
// This function is not range checked and will fail if max < min
integer random_integer(integer min, integer max)
{
return min + (integer)(llFrand(max - min + 1));
}
say(string message)
{
llSay(0, message);
}
default
{
touch_start(integer total_number)
{
// *near* 50:50 chance of "Heads" vs. "Tails"
if (coin_toss()) say("Heads");
else say("Tails");
integer n1 = random_integer(2, 8); // Return a random number between 2 and 8
say("I chose a " + (string)n1);
}
}
// Example for generating an uniformly distributed integer with more than
// 16 million possible values; in particular, this code will generate
// 500,000,000 possible values, ranging from 0 to 499,999,999 inclusive.
//
// The method consists of not using llFrand() on a number larger than 16,777,216
// (2^24) but to divide the range into two numbers that are both less than that,
// using a scheme of the form (integer)llFrand(a)*b + (integer)llFrand(b), where
// a*b gives the desired range.
//
// For prime ranges, or ranges with a prime factor greater than 2^24, a rejection
// scheme should be used (use this method to generate a number slightly above the
// target range, and reject it and generate a new one if it exceeds the maximum).
default
{
state_entry()
{
integer rand = (integer)llFrand(500)*1000000 + (integer)llFrand(1000000);
llOwnerSay("Here's a random number between 0 and 499,999,999 inclusive: " + (string)rand);
}
}
The following code produces the most possibilities for random negative integers (suitable for use as channel numbers for example)
integer rand = 0x80000000 | (integer)llFrand(65536) | ((integer)llFrand(65536) << 16);
// Simple integer random number tester
// Contributed by Mephistopheles Thalheimer
// This is a random number tester designed to give a quick visual explanation
// and proof of why some random integer functions just do not work. In general,
// with any random number generator, if you can see a pattern emerging, then
// chances are, the function is not random.
// The test case given "silly_random_integer( .. )" shows the type of pitfalls
// that can happen. Superficially, it would seem like a good candidate. I
// thought so, and in fact mooted it in a discussion, however, a bit of thought
// reveals that the first and last bin are only collecting rounded results from
// half the float space as the rest of the integers. They are therefore
// under-represented in output, and the generator is flawed.
integer random_integer(integer min, integer max)
{
return min + (integer)llFrand(max - min + 1);
}
integer silly_random_integer(integer min, integer max)
{
return min + (integer)(llRound(llFrand(max - min))); // Looks good, but does not work
}
say(string message)
{
llSay(0, message);
}
// Simple integer random number tester
// Contributed by Mephistopheles Thalheimer
list bins;
integer MIN = 2; // The minimum integer you want
integer MAX = 5; // The maximum integer you want
integer NUMBER_OF_TRIES = 10000; // The bigger the better.. but slower
default
{
state_entry()
{
say("Bin tester ready.");
bins = [];
}
touch_start(integer total_number)
{
say("Started, be patient");
integer i;
integer r;
integer range = MAX - MIN;
for (i = 0; i <= range; ++i)
{
bins += [ 0 ];
}
integer v;
integer out_of_range;
for (i = 0; i < NUMBER_OF_TRIES; ++i)
{
// Replace the next line with the function you are testing
r = silly_random_integer(MIN, MAX);
// Note the output on the next line has about 0.5 expected hits on the first and last bin
// r = random_integer(MIN, MAX);
if (r > MAX || r < MIN)
{
out_of_range++;
}
else
{
v = llList2Integer(bins, r - MIN);
bins = llListReplaceList(bins, [++v], r - MIN, r - MIN);
}
}
for (i = 0; i <= range; ++i)
{
say("Bin #" + (string)(i + MIN) + " = " + (string)llList2Integer(bins, i));
}
say("Number out of range = " + (string)out_of_range);
}
}
//Exponential distribution
//
// Contributed by Pat Perth on October 5th 2013
// No rights reserved
//
// Return an exponentially distributed random number with expected value 'mean_value'
//
// Reference: Wikipedia article "Exponential distribution", in particular the section
// entitled "Generating exponential variates" at
//
// http://en.wikipedia.org/wiki/Exponential_distribution (visited on October 5th 2013)
//
// The exponential distribution is often an appropriate way to simulate waiting times
// of the sort "It takes about x seconds for <something> to happen." For
// example, if you want to trigger a rain shower "about every seven days", use
//
// time_between_rain = random_exponential(7.0 * 24.0 * 60.0 * 60.0) ;
//
// in an llSleep(...) or llSetTimerEvent(...) call.
//
// Please notice the negative sign in the return value.
float random_exponential(float mean_value)
{
return -mean_value * llLog(llFrand(1.0));
}
|