Difference between revisions of "LlFrand"

From Second Life Wiki
Jump to navigation Jump to search
(Added some examples, functions and discussions by myself and Hg Beeks. Added a bin tester example.)
Line 24: Line 24:
   
   
// Sometimes it is useful to get a random integer over a given range.  This is a suprisingly tricky and emotive subject
// Sometimes it is useful to get a random integer over a given range.  This is a suprisingly tricky and emotive subject
// and has caused endless discussion on the groups.  Here are some solutions.
// and has caused endless discussion on the scripting groups.  Here are some solutions.


 
// Meph: Expand the range by 1.0 to ensure equal bin spacing on ends and in the middle of the range
// Random integer generator
// and then the integer cast catches the negative outlier (-0.5) when it rounds towards zero.
// Contributed by Mephistopheles Thalheimer
// Returns a psuedo-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 which catches the positive or negative outliers (-0.5) and rounds  
// them back towards zero.
 
// Caveats:  This function is not range checked
//          Because an LSL floating point number is only a subset of real numbers and does not have infinite granularity,
//          one integer output ( min ) will be over-represented by a tiny amount.  The probability of over-representation
//          for a given call, is inversely proportional to the range and is a maximum of 1 / 8388608 when the range is 1.


integer random_integer( integer min, integer max )
integer random_integer( integer min, integer max )
{
{
  // Caution, not range checked
   return min + (integer)( llRound( llFrand( max - min + 1 ) - 0.5 ) );   
   return min + (integer)( llRound( llFrand( max - min + 1 ) - 0.5 ) );   
}
}


   
   
// Hg: While it IS technically possible to get the maximum value in llFrand and cause this to return a value above the range,  
// Random integer generator and discussion
// Contributed by Hg Beeks
// Returns a psuedo-random integer in the range of min to max inclusive but is slightly more efficient ( but with risk ) to Mephs above.
 
// While it IS technically possible to get the maximum value in llFrand and cause this to return a value above the range,  
// the likelyhood of this occuring is 1:1,000,000 for every whole number in the range - You will have a 1:5,000,000 chance of  
// the likelyhood of this occuring is 1:1,000,000 for every whole number in the range - You will have a 1:5,000,000 chance of  
// getting 5 if doing llFrand(5), at the very least likelyhood. Testing also seems to imply that llFrand goes past the six-digit  
// getting 5 if doing llFrand(5), at the very least likelyhood. Testing also seems to imply that llFrand goes past the six-digit  
Line 63: Line 77:
         llSay( PUBLIC_CHANNEL, "I chose a " + (string)n1 );
         llSay( PUBLIC_CHANNEL, "I chose a " + (string)n1 );
   
   
         integer n2 = fast_random_integer( 3, 10 ); // Returns a (slightly faster) random integer between 3 and 10  
         integer n2 = fast_random_integer( 3, 10 ); // Returns a (slightly faster) random integer between 3 and 10.
         llSay( PUBLIC_CHANNEL, "I chose a " + (string)n2 );
         llSay( PUBLIC_CHANNEL, "I chose a " + (string)n2 );
   
   
     }
     }
}
}
   
 
</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)( llRound( llFrand( max - min + 1 ) - 0.5 ) ); 
}
 
integer silly_random_integer( integer min, integer max )
{
  return min + (integer)( llRound( llFrand( max - min ) ) );  // Looks good, but does not work
}
 
 
// 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_TRYS  = 10000;    // The bigger the better.. but slower
 
default
{
    state_entry()
    {
        llSay( PUBLIC_CHANNEL, "Bin tester ready.");
        bins = [];
    }
 
    touch_start(integer total_number)
    {
       
        llSay( PUBLIC_CHANNEL, "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_TRYS; ++i )
        {
            r = silly_random_integer( MIN, MAX );  // Replace this 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 = random_integer( MIN, MAX );
            //r = fast_random_integer( MIN, MAX );
           
            if( r > MAX || r < MIN ) out_of_range++;
           
            v = llList2Integer( bins, r - MIN );
           
            bins = llListReplaceList( bins, [ ++v ], r - MIN, r - MIN );
           
        }
 
        for( i = 0; i <= range; ++i )
        {
            llOwnerSay( "Bin #" + (string)( i + MIN ) + " = " + (string)llList2Integer( bins, i ) );   
        }
       
        llOwnerSay( "Number out of range = " + (string)out_of_range );
    }
}




</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.
|also_header
|also_header

Revision as of 06:59, 16 December 2008

Summary

Function: float llFrand( float mag );
0.0 Forced Delay
10.0 Energy

Returns a float that is pseudo random number in the range [0.0,mag) or (mag, 0.0].
The sign of mag matches the return.

• float mag Any valid float value

Specification

returns a pseudo random number in range [0.0, mag) or (mag, 0.0], depending upon the sign of mag.

Caveats

The random number generator is not a source of entropy.

Examples

<lsl>

// Tosses a coin, giving a *near* 50:50 chance of a result.

integer coin_toss() {

 if( llFrand(1.) < .5 ) return TRUE;
 return FALSE;

}


// Sometimes it is useful to get a random integer over a given range. This is a suprisingly tricky and emotive subject // and has caused endless discussion on the scripting groups. Here are some solutions.


// Random integer generator // Contributed by Mephistopheles Thalheimer // Returns a psuedo-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 which catches the positive or negative outliers (-0.5) and rounds // them back towards zero.

// Caveats: This function is not range checked // Because an LSL floating point number is only a subset of real numbers and does not have infinite granularity, // one integer output ( min ) will be over-represented by a tiny amount. The probability of over-representation // for a given call, is inversely proportional to the range and is a maximum of 1 / 8388608 when the range is 1.

integer random_integer( integer min, integer max ) {

 return min + (integer)( llRound( llFrand( max - min + 1 ) - 0.5 ) );  

}


// Random integer generator and discussion // Contributed by Hg Beeks // Returns a psuedo-random integer in the range of min to max inclusive but is slightly more efficient ( but with risk ) to Mephs above.

// While it IS technically possible to get the maximum value in llFrand and cause this to return a value above the range, // the likelyhood of this occuring is 1:1,000,000 for every whole number in the range - You will have a 1:5,000,000 chance of // getting 5 if doing llFrand(5), at the very least likelyhood. Testing also seems to imply that llFrand goes past the six-digit // lead that float returns, which means that the likelyhood could, in fact, be lower than this. However, decreasing // the +1 to .999999 in fact affects the probability and would make the highest value you want just a smidgen less likely.

integer fast_random_integer( integer min, integer max ) {

 return min + (integer)llFrand( max - min + 1 );

}


default {

   touch_start(integer total_number)
   {
       // When touched, say "Heads" with probability 0.5, 
       // otherwise, say "Tails."
       if ( coin_toss() )
           llSay(0, "Heads");
       else
           llSay(0, "Tails");

       integer n1 = random_integer( 2, 8 ); // Return a random number between 2 and 8
       llSay( PUBLIC_CHANNEL, "I chose a " + (string)n1 );

       integer n2 = fast_random_integer( 3, 10 ); // Returns a (slightly faster) random integer between 3 and 10.
       llSay( PUBLIC_CHANNEL, "I chose a " + (string)n2 );

   }

}

</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)( llRound( llFrand( max - min + 1 ) - 0.5 ) );  

}

integer silly_random_integer( integer min, integer max ) {

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

}


// 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_TRYS = 10000; // The bigger the better.. but slower

default {

   state_entry()
   {
       llSay( PUBLIC_CHANNEL, "Bin tester ready.");
       bins = [];
   }
   touch_start(integer total_number)
   {
       
       llSay( PUBLIC_CHANNEL, "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_TRYS; ++i )
       {
           r = silly_random_integer( MIN, MAX );   // Replace this 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 = random_integer( MIN, MAX );
           //r = fast_random_integer( MIN, MAX );
           
if( r > MAX

Useful Snippets

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

Notes

The random number generator is not a source of entropy.

The sequence of random numbers are shared across the entire 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.

See Also

Functions

•  llListRandomize

Deep Notes

Signature

function float llFrand( float mag );