Difference between revisions of "LlFrand"

From Second Life Wiki
Jump to navigation Jump to search
(Added code for a function that returns an exponentially distributed random variable with a specified mean value. I wrote every word of it all by myself.)
m (better readability on mobile screens and 0 >> PUBLIC_CHANNEL and fixed grammar)
Line 24: Line 24:
         float randomFloat = 10.0 + llFrand(-5.0);
         float randomFloat = 10.0 + llFrand(-5.0);


         llSay(0, (string) randomFloat);
         llSay(PUBLIC_CHANNEL, (string) randomFloat);
     }
     }
}
}
Line 36: Line 36:
         float randomFloat = 10.0 - llFrand(5.0);
         float randomFloat = 10.0 - llFrand(5.0);


         llSay(0, (string) randomFloat);
         llSay(PUBLIC_CHANNEL, (string) randomFloat);
     }
     }
}
}
Line 42: Line 42:
{{!}}}
{{!}}}
<lsl>
<lsl>
// Tosses a coin, giving a *near* 50:50 chance of a result.
// *near* 50:50 chance of "Heads" vs. "Tails"
integer coin_toss()
integer coin_toss()
{
{
  if( llFrand(1.) < .5 ) return TRUE;
    if (llFrand(1.0) < 0.5) return TRUE;
  return FALSE;
    return FALSE;
}
}


// Sometimes it is useful to get a random integer over a given range.  This is a surprisingly tricky and emotive subject
// Sometimes it is useful to get a random integer over a given range.  This is
// and has caused endless discussion on the scripting groups.
//  a surprisingly tricky and emotive subject and has caused endless discussion
// The primary cause of probability errors when employing llFrand is to have a varying bin size on the edges of the range.
//  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.
// As the bracket notation indicates, [0.0, mag), the function is inclusive of
// Because an LSL floating point number is only a subset of real numbers and does not have infinite granularity, this schema
//  the 0.0 and exclusive of the entered value. Because an LSL floating point
// will work for any float greater than float t = 1.175494351e-38; at which value the function will
//  number is only a subset of real numbers and does not have infinite
// return only zero. At a float beyond this, a math error occurs.
//  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
// Random integer generator
//  float beyond this, a math error occurs.
// Contributed by Mephistopheles Thalheimer, original function posited by Hg Beeks


// Returns a pseudo-random integer in the range of min to max inclusive.
// Random integer generator:
//      Contributed by Mephistopheles Thalheimer,
//      original function posted by Hg Beeks


// Rationale: Expands the range by 1.0 to ensure equal bin spacing on ends relative to the middle of  
// Returns a pseudo-random integer in the range of min to max inclusive.
// 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
// 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.


integer random_integer( integer min, integer max )
//  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)
{
{
  return min + (integer)( llFrand( max - min + 1 ) );
    llSay(PUBLIC_CHANNEL, message);
}
}


Line 77: Line 89:
     touch_start(integer total_number)
     touch_start(integer total_number)
     {
     {
        // When touched, say "Heads" with probability 0.5,
//     *near* 50:50 chance of "Heads" vs. "Tails"
        // otherwise, say "Tails."
         if (coin_toss()) say("Heads");
         if ( coin_toss() )
         else            say("Tails");
            llSay(0, "Heads");
 
         else
         integer n1 = random_integer(2, 8); // Return a random number between 2 and 8
             llSay(0, "Tails");
         say("I chose a " + (string)n1);
 
         integer n1 = random_integer( 2, 8 ); // Return a random number between 2 and 8
         llSay( PUBLIC_CHANNEL, "I chose a " + (string)n1 );
     }
     }
}</lsl>
}</lsl>


<lsl>// Simple integer random number tester
<lsl>
// Simple integer random number tester
// Contributed by Mephistopheles Thalheimer
// Contributed by Mephistopheles Thalheimer


// This is a random number tester designed to give a quick visual explanation and proof of why some
// This is a random number tester designed to give a quick visual explanation
// random integer functions just do not work.
//  and proof of why some random integer functions just do not work. In general,
// In general, with any random number generator, if you can see a pattern emerging, then chances are,  
// with any random number generator, if you can see a pattern emerging, then
// the function is not random.
//  chances are, the function is not random.


// The test case given "silly_random_integer( .. )" shows the type of pitfalls that can happen. Superficially,
// The test case given "silly_random_integer( .. )" shows the type of pitfalls
// 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 can happen. Superficially, it would seem like a good candidate.  I
// that the first and last bin are only collecting rounded results from half the float space as the rest of the integers.
//  thought so, and in fact mooted it in a discussion, however, a bit of thought
// They are therefore under-represented in output, and the generator is flawed.  
// 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 )
integer random_integer(integer min, integer max)
{
{
  return min + (integer)llFrand( max - min + 1 );
    return min + (integer)llFrand(max - min + 1);
}
}


integer silly_random_integer( integer min, integer max )
integer silly_random_integer(integer min, integer max)
{
{
  return min + (integer)( llRound( llFrand( max - min ) ) ); // Looks good, but does not work
    return min + (integer)(llRound(llFrand(max - min))); // Looks good, but does not work
}
}


say(string message)
{
    llSay(PUBLIC_CHANNEL, message);
}


// Simple integer random number tester
// Simple integer random number tester
// Contributed by Mephistopheles Thalheimer
// Contributed by Mephistopheles Thalheimer


list bins;
list bins;


integer     MIN            = 2;       // The minimum integer you want
integer MIN            = 2;                             // The minimum integer you want
integer     MAX            = 5;       // The maximum integer you want
integer MAX            = 5;                             // The maximum integer you want


integer     NUMBER_OF_TRIES = 10000;   // The bigger the better.. but slower
integer NUMBER_OF_TRIES = 10000;                         // The bigger the better.. but slower


default
default
Line 129: Line 145:
     state_entry()
     state_entry()
     {
     {
         llSay( PUBLIC_CHANNEL, "Bin tester ready.");
         say("Bin tester ready.");
         bins = [];
         bins = [];
     }
     }
Line 135: Line 151:
     touch_start(integer total_number)
     touch_start(integer total_number)
     {
     {
       
 
         llSay( PUBLIC_CHANNEL, "Started, be patient" );
         say("Started, be patient");
       
 
         integer i;
         integer i;
         integer r;
         integer r;
       
 
         integer range = MAX - MIN;
         integer range = MAX - MIN;
       
 
         for( i = 0; i <= range; ++i )
         for (i = 0; i <= range; ++i)
         {
         {
             bins += [ 0 ];  
             bins += [ 0 ];
         }
         }
       
 
         integer v;
         integer v;
         integer out_of_range;
         integer out_of_range;
       
 
         for( i = 0; i < NUMBER_OF_TRIES; ++i )
         for (i = 0; i < NUMBER_OF_TRIES; ++i)
         {
         {
             r = silly_random_integer( MIN, MAX );   // Replace this with the function you are testing
//          Replace the next line with the function you are testing
                                                    // Note the output on this one has about 0.5 expected hits on the first and last bin
             r = silly_random_integer(MIN, MAX);
            //r = random_integer( MIN, MAX );
 
           
//         Note the output on the next line has about 0.5 expected hits on the first and last bin
             if( r > MAX || r < MIN )
//         r = random_integer(MIN, MAX);
             {  
 
             if (r > MAX || r < MIN)
             {
               out_of_range++;
               out_of_range++;
             }
             }
             else
             else
             {
             {
               v = llList2Integer( bins, r - MIN );
               v = llList2Integer(bins, r - MIN);
               bins = llListReplaceList( bins, [ ++v ], r - MIN, r - MIN );
               bins = llListReplaceList(bins, [++v], r - MIN, r - MIN);
             }
             }
         }
         }


         for( i = 0; i <= range; ++i )
         for (i = 0; i <= range; ++i)
         {
         {
             llOwnerSay( "Bin #" + (string)( i + MIN ) + " = " + (string)llList2Integer( bins, i ) );  
             say("Bin #" + (string)(i + MIN) + " = " + (string)llList2Integer(bins, i));
         }
         }
       
 
         llOwnerSay( "Number out of range = " + (string)out_of_range );
         say("Number out of range = " + (string)out_of_range);
     }
     }
}</lsl>
}
<lsl>//Exponential distribution
</lsl>
<lsl>
//Exponential distribution
//
//
// Contributed by Pat Perth on 5 October 2013
// Contributed by Pat Perth on October 5th 2013
// No rights reserved
// No rights reserved
//
//
// Return an exponentially distributed random number with expected value 'mean_value'  
// Return an exponentially distributed random number with expected value 'mean_value'
//
//
// Reference: Wikipedia article "Exponential distribution", in particular the section
// Reference: Wikipedia article "Exponential distribution", in particular the section
// entitled "Generating exponential variates" at
// entitled "Generating exponential variates" at
//
//
// http://en.wikipedia.org/wiki/Exponential_distribution
// http://en.wikipedia.org/wiki/Exponential_distribution (visited on October 5th 2013)
//
// on 5 October 2013
//
//
// The exponential distribution is often an appropriate way to simulate waiting times
// 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
// 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
// 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) ;
// time_between_rain = random_exponential(7.0 * 24.0 * 60.0 * 60.0) ;
//
//
// in an llSleep(...) or llSetTimerEvent(...) call.
// in an llSleep(...) or llSetTimerEvent(...) call.
//
//
// Please notice the negative sign in the return value.
// Please notice the negative sign in the return value.


float random_exponential(float mean_value)
float random_exponential(float mean_value)
{
{
return -mean_value * llLog(llFrand(1.0));
    return -mean_value * llLog(llFrand(1.0));
}
}
</lsl>
</lsl>
|helpers=[[Pseudo-random_Number_Generator]] - Suitable for apps which require repeatable results that feel random.
|helpers=[[Pseudo-random_Number_Generator]] - Suitable for apps which require repeatable results that feel random.

Revision as of 10:05, 8 October 2013

Summary

Function: float llFrand( float mag );

Returns a float that is pseudo random in the range [0.0, mag) or (mag, 0.0].[1]
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.
    • Integers outside the range [-224, +224] may not be accurately represented (this is an inherent limitation of the float type).
    • Integers generated with this function cannot contain more than 24 random bits, yielding 224 possible final values.
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> // 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(PUBLIC_CHANNEL, 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

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 );