llFrand

From Second Life Wiki
Revision as of 10:00, 22 April 2014 by Omei Qunhua (talk | contribs) (Don't ask people to read a whole article on interval notation in order to understand this function!)
Jump to navigation Jump to search

Summary

Function: float llFrand( float mag );

Returns a float that is pseudo random in the range [0.0, mag) or (mag, 0.0].[1]
This means that the returned value can be any value in the range 0.0 to mag including 0.0, but not including the value of mag itself. The sign of mag matches the return.

• float mag Any valid float value

When converting the float to an integer, be sure to use an integer typecast (integer) and not one of the rounding functions (llRound, llFloor, llCeil). The integer typecast is the only method guaranteed not to skew the distribution of integer values.

Caveats

  • The random number generator is not a source of entropy.
    • The sequence of random numbers are shared across the entire simulator process, and not independently seeded. Therefore, the pseudo random number generation is not suitable for any application which requires completely predictable or completely unpredictable results.
  • It should be remembered that when passing llFrand an integer as the mag, it will be implicitly typecast to a float.
  • Many integers outside the range [-224, +224] can not be represented in a float (this is an inherent limitation of the float type); for example, outside that range no odd integers will appear. For that reason, when converting the resulting float to integer, it is impossible to generate more than 224+1 uniformly distributed values, and it's also impossible to generate more than 9*223+1 or about 75 million different integers in total. Two llFrand calls may be needed to obtain the desired integer range; see examples below.
All Issues ~ Search JIRA for related Bugs

Examples

Method one: returns float within (5.0, 10.0] Method two: returns float within (5.0, 10.0]
<lsl>

default {

   state_entry()
   {
       float randomFloat = 10.0 + llFrand(-5.0);
       llSay(PUBLIC_CHANNEL, (string) randomFloat);
   }

} </lsl>

<lsl> default {

   state_entry()
   {
       float randomFloat = 10.0 - llFrand(5.0);
       llSay(PUBLIC_CHANNEL, (string) randomFloat);
   }

} </lsl>

<lsl> // *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(PUBLIC_CHANNEL, 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);
   }

}</lsl>

<lsl> // 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);
   }

} </lsl>

The following code produces the most possibilities for random negative integers (suitable for use as channel numbers for example) <lsl>

integer rand = 0x80000000

Useful Snippets

Pseudo-random_Number_Generator - Suitable for apps which require repeatable results that feel random.

See Also

Functions

•  llListRandomize

Deep Notes

Search JIRA for related Issues

Footnotes

  1. ^ The ranges in this article are written in Interval Notation.

Signature

function float llFrand( float mag );