Page 1 of 1

fRand() range

Posted: Fri Dec 15, 2017 4:13 pm
by Barbie
Recently I saw this
ScriptWarning: GreenBlob MH-Fuedal(SB)V2.GreenBlob72 (Function UnrealShare.GreenBlob.Setup:0014) Accessed array out of bounds (5/5)
and in GreenBlob.uc

Code: Select all

simulated function Setup(vector WallNormal){
	Texture = BlobTypes[int(Frand()*5)];
	Velocity = VRand()*140*FRand()+WallNormal*250;
	DrawScale = FRand()*0.3 + 0.2;
}
what made me curious about the range of fRand(). Wiki says Returns a random number between 0 and 1, and above ScriptWarning supports this.

Quite crooked because all other random generators I know have the range

Code: Select all

Min <= RandValue < Max

Re: fRand() range

Posted: Fri Dec 15, 2017 5:42 pm
by JackGriffin
Simple coding error. I've done this myself. Frand and Rand are different functions for different uses along with some overlap between them. Should be:

Code: Select all

    Texture = BlobTypes[int(Rand(5))];
This will return an integer from 0 to 4 that corresponds with the textures declared in def props

Code: Select all

 
     BlobTypes(0)=Texture'UnrealShare.Effects.GreenBlob1'
     BlobTypes(1)=Texture'UnrealShare.Effects.GreenBlob2'
     BlobTypes(2)=Texture'UnrealShare.Effects.GreenBlob3'
     BlobTypes(3)=Texture'UnrealShare.Effects.GreenBlob4'
     BlobTypes(4)=Texture'UnrealShare.Effects.GreenBlob5'
If you want to return integers but need a non-zero return just do a little math adjustment

Code: Select all

    Texture = BlobTypes[(Rand(5)+1)];
Now it will return from 1 to 5.

I know you know this B, I'm just starting the discussion for someone that is learning via a google search.

Re: fRand() range

Posted: Fri Dec 15, 2017 6:10 pm
by sektor2111
Array accessed is too big, decrease 1 value. This is what I did and... it works properly.

Code: Select all

// ...int(Frand()*5) becomes
...int(Frand()*4)
That simple.

Re: fRand() range

Posted: Fri Dec 15, 2017 6:12 pm
by JackGriffin
Yeah, this is the overlap I mentioned and it would work but it's cleaner to just deal with integers from the start if that's the return you need.

Re: fRand() range

Posted: Fri Dec 15, 2017 6:56 pm
by Higor
Let's see,

FRAND:
Rand() [0-32767]> converted to float > divided by 32767.f

Then the conversion:
Substract 0.5f > round (up or down)

The FPU instructions 'may' give you an accuracy problem.

Re: fRand() range

Posted: Sat Dec 16, 2017 10:29 am
by Barbie
Thanks for all statements - what I wanted to say is that including the maximum value into the range is unexpected, at least for me and the coder of GreenBlob.Setup() :roll:
sektor2111 wrote:Array accessed is too big, decrease 1 value. This is what I did and... it works properly.

Code: Select all

// ...int(Frand()*5) becomes
...int(Frand()*4)
That simple.
Hmmm, I think that array index 4 will not get as many matches as the others:
0 <= x < 1 => int(x) = 0
1 <= x < 2 => int(x) = 1
2 <= x < 3 => int(x) = 2
3 <= x < 4 => int(x) = 3
x = 4 => int(x) = 4

Re: fRand() range

Posted: Sat Dec 16, 2017 11:00 am
by sektor2111
If you do what I said I'll bet that you'll vaporize those errors - code can be conformed because it's server-side.

Re: fRand() range

Posted: Sat Dec 16, 2017 1:35 pm
by nogardilaref
While FRand() may equalize to 1.0, it should have always a 1/32768 chance in this case (that's around 0.0031%), considering what Higor said about FRand, so just decrementing the integer multiplication by 1 is only going to make the last element to have this much of a change to actually be selected over time, while the rest will have a much higher chance to appear.

In other words, if you have 3 elements, and you are counting with FRand() equalizing to 1.0, then the chance of each one is not 33%, but rather the chance of the 2 first elements will be almost 50% each (around 49.995% specifically), while the last one will only appear in 0.0031% of the times.

If you are working with integers, especially to select elements from an array, you're better off with Rand which does exclude the Max value as a possible value, so you don't have to worry about this.
If you however absolutely need a floating point random generator, and you need to exclude the 1.0 from one of the possible outcomes, you can just create your own random function:

Code: Select all

static function float frandom()
{
    local float f;

    f = frand();
    if (f == 1.0) {
        f = 0.0;
    }
    return f;
}
In other words, whenever it's 1.0, return 0.0 instead. This will effectively make 0.0 being the number with double the chances of appearing, but that's just 2 in 32768, or 0.0061%, so it's negligible in my opinion.

Another more fair way would be:

Code: Select all

static function float frandom()
{
    return float(rand(16777216)) / 16777216.0;
}
By taking advantage of the fact that Rand excludes the Max as being a possible value, although if it didn't, since we're working with integers here, it would be trivial to just use 16777215 instead inside Rand.
But this would be just a slightly slower way of doing, processing wise, but it's also a negligible difference.
Also,16777216 is a number which represents the maximum integer number a 32 bits float can represent without loosing precision.

Re: fRand() range

Posted: Sat Dec 16, 2017 5:52 pm
by sektor2111
If you want a conformed package (THAT is a stock code), Forget any new function - I know what I'm saying. K.I.S. is the rule here (Keep It Simple).

Re: fRand() range

Posted: Sat Dec 16, 2017 7:03 pm
by Higor
FRand() in UT can return 1
Use Rand() or multiply like this: *4.99