Don't click here unless you want to be banned.

LSL Wiki : llFrand

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl814.us.archive.org
float llFrand(float max)

Returns a random float x from the interval [0.0, max), that is, 0.0 <= x < max. Ideally, the values returned would be uniformally distributed, but it has been reported that they are not very uniform.

To get a random float from (min, max) use something like

float randBetween(float min, float max)
{
    return llFrand(max - min) + min;
}

Integers


There are many cases where a random integer value would be useful: lists, channels, constants, etc. Try something like
integer randInt(integer n)
{
     return (integer)llFrand(n + 1);
}

integer randIntBetween(integer min, integer max)
{
    return min + randInt(max - min);
}

It should be noted, that llFrand can only ever return 24 random bits.

Rounding

There are a couple different functions for converting a float to an integer, in addition to casting. They will not yield evenly distributed results. The correct solution is to use an integer typecast (integer).

//right way
integer random = (integer)llFrand(4.0);//will return an integer 0 to 3, all with equal probabilities (more or less).

A first idea might be to use llRound but that has problems with the distributions. For example:

//wrong, do not do this.
integer random = llRound(llFrand(4.0));

In this case the values will range from 0 to 4 which is more intuitively obvious than the example below. However, the values returned by llFrand that will result in the integer 0 range from 0.0 to 0.5, and the values that will result in the integer 1 will be 0.5000001 to 1.5. As you can see the range for integer 1 is twice as large. That means a 1 will be "randomly" generated twice as often as a 0 which is probably not desired. The same effect happens at the far end with the integer 4.

Using llCeil is a bit safer, but still wrong:

//still wrong, do not do this (unless the input to llFrand is negitive, at which point it will do the same thing as an integer typecast)
integer random = llCeil(llFrand(4.0));

By rounding up it seems like this would result in a straight forward range from 1 to 4. It's unlikely, but possible, that llFrand will return a pure 0.0 value. In that case llCeil will not round up and it will return anomalous 0 values in very disproportionate frequency to the other values. The 0 is actually stealing that bit of probability from the 4, so an integer 4 will be infinitesimally less likely to occur than the others.

//still wrong, do not do this (unless the input to llFrand is positive, at which point it will do the same thing as an integer typecast)
integer random = llFloor(llFrand(5.0));

Using 5.0 for the input isn't obvious but results in float numbers between 0.0 and 4.99999. The floor function truncates the decimal. This results in values of 0 through 4. This is a perfect distribution of probability and the numbers drop right into list usage being zero indexed. So think of the input number as how many possible integers desired and, remember, they start with 0. But if input to llFrand is negitive this will have the same problem as llCeil

Solutions

The correct solution is to use the (integer) typecast. For example, to get a random integer ranging from 0 to 4:

integer random = (integer) llFrand (5.0);


image courtesy of http://xkcd.com/


Functions | Math
Comments [Hide comments/form]
I am changing 0.0 < return value <= max to 0.0 <= return value < max. I built probably about 2 dozen gambling machines, maybe more, and I am 99.9% sure that is the way it works. I'm adding this comment so perhaps whoever disagrees can tell me why they disagree?
-- AmaOmega (2004-07-10 23:08:26)
I'm changing '0.0 <= return value < max' to '0.0 <=return value <= max'.

See the output of this script for details:

default {
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }

    touch_start(integer total_number)
    {
        llSay(0, (string)llFrand(0.000002));
    }
}
-- HuntingHare (2004-09-09 09:17:45)
Don't. What you see is simply the typecasting from float to string rounding the real value at the last decimal. Try this:

llSay(0, (string)(llFrand(0.000002) * 100));
-- EzharFairlight (2004-09-09 10:56:59)
HuntingHare, they look equal but they are not equal. You need to be a bit more careful with floats than with integers, or they'll bite ya. Try this (poke it a few times for the full effect):

default
{
    touch_start(integer total_number)
    {
        float arg = 0.000002;
        float rnd = llFrand(arg);
        if (arg == rnd) {
            llSay(0, "equal");
        } else {
            llSay(0, "not equal");
            llSay(0, (string)(arg * 1000000.0));
            llSay(0, (string)(rnd * 1000000.0));
        }
    }
}

I think AmaOmega is correct and this should be changed back again.
-- AlexanderDaguerre (2004-09-09 11:13:55)
Most floating-point libraries have constants defined to deal with the inherent inaccuracy of floating-point numbers. ISO C99 defines, as examples:
FLT_EPSILON 1E-5
DBL_EPSILON 1E-9
LDBL_EPSILON 1E-9

This is the minimum difference of a number from 1 which can be accurately distinguished from 1.

What is the epsilon on LSL? 32-bit floats, on Linux platforms? Are they using their own math library?
-- HuntingHare (2004-09-09 18:04:16)
floats in LSL appear to be 32-bit IEEE 854 floats, which is to say they have one bit of sign, eight bits of exponent and 23 bits (plus one hidden bit) of mantissa. The smallest number that is distinguishable from 1.0 is therefore 2^-23, or around 1.19E-7. I checked this with a script.

LSL will probably not be using its own math library, as such. Almost certainly it just uses the facilities of the language the simulator code is written in, which is presumably C or C++.
-- AlexanderDaguerre (2004-09-11 09:53:31)
When looking to select an object randomly from a number of objects (e.g inventory items held in a list) I found that the following piece of code is more effective than simply using: llFrand(count - 1);

Here's my alternative code:
float limit = llPow(count,3.0); Stores a nice big number, bigger numbers for bigger lists, modify this if you fear your lists becoming huge!
integer item = llRound(llFrand(limit)) % count;
Returns 0 to (count - 1), add one to this if you want 1 to count!

count is the number of items (in a list or otherwise). For some reason doing this seems to give a more even distribution of selections than the first method. Perhaps it's due to using larger numbers and the modulus operator, I don't know.
-- HaravikkMistral (2005-11-20 15:03:04)
Added some info on random integers.
-- ReadyJack (2006-04-01 18:01:58)
No need to add updates to comments as it's obvious what is added in a page's revision history.
-- EepQuirk (2006-04-02 05:45:43)
lsl was writen in c++.
for information on floats try: float
-- BlindWanderer (2006-04-02 12:51:58)
Why did you remove the crosstalk-safe example, Chad?
-- EepQuirk (2006-04-04 21:30:09)
It's not cross talk safe, it does not do as advertised.
It will generate a random number sure, but it won't ensure it isn't the same as a previous result.
-- BlindWanderer (2006-04-04 23:59:52)
I registered to comment on this, after seeing the first comment.
The numbers Frand includes are [0,x), where x is your max.
If you've ever been through calculus, even precal, in fact algebra two, you'd recognize the interval notation, where [] includes the number, and () limits up to that number, so [0,50) would be 0.0 <= return < 50.
-- EagleBird (2006-08-09 22:06:27)
Using a simple random int for a dialog channel would work fine for the vast majority of people. What reasonable scheme accessible to a new scripter would be perfect?

Not a big deal of course, but having examples that inspire thoughts on practical purposes for new scripters is a good thing in my mind. The comment was a harmless way to pop it out.
-- ReadyJack (2006-08-27 02:51:42)
The example for using llFloor says it's wrong, unless the input to llFrand is positive. In other words, it's correct unless the input to llFrand is negative. Yet this raises a couple of issues.

First, it's not even clear whether negative numbers are allowed as input to llFrand. The description here doesn't explicitly say it's prohibited, but saying that it returns a number in the range [0.0, max) implies it; [0.0, -5) is the empty set, at least according to the definition I use. It would have to be written (-5, 0.0]. I wonder if llFrand has ever been tested to see if a negative number results in (min, 0.0] or [min, 0.0) or some other permutation. If it works by taking the absolute value, calculating the random number, and then adjusting the sign if necessary, then no problem. In any event, passing a negative number to llFrand is such an unlikely thing to do, that I'd prefer to say that it works, with a caveat about negative numbers.

A different reason for avoiding llFloor is that according to the documentation for float, llFloor is 50% slower than (integer). That's an obvious opportunity for optimization, but assuming it's true, it's a decent enough reason for preferring (integer). Pesonally, however, I'd recommend to novices that they use llFloor instead, simply because it clarifies what's going on.
-- MarsConsult (2007-07-04 10:30:57)
Mathematically speaking you are correct, the way llFrand is explained using 0.0 <= x <= max is misleading. It takes a bit of "creative" thinking for this mathematical definition to work.

Negative numbers do work just fine and are used very frequently for dialogs and object to object communication.

llFloor is slower then (integer) but it is important to realize that they are different. The results are the same for positive values but different for negative. llFloor rounds down and (integer) drops bits. Example: (integer)(-1.32) = -1 while llFloor( -1.32 ) = -2
-- EvoCommons (2007-07-06 02:42:27)
Attach a comment to this page: