fRand() range

Discussions about Coding and Scripting
User avatar
Barbie
Godlike
Posts: 2107
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

fRand() range

Post by Barbie » Fri Dec 15, 2017 4:13 pm

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
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett

JackGriffin
Godlike
Posts: 3765
Joined: Fri Jan 14, 2011 1:53 pm
Personal rank: -Retired-

Re: fRand() range

Post by JackGriffin » Fri Dec 15, 2017 5:42 pm

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.
Last edited by JackGriffin on Fri Dec 15, 2017 6:13 pm, edited 2 times in total.
So long, and thanks for all the fish

User avatar
sektor2111
Godlike
Posts: 5336
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: fRand() range

Post by sektor2111 » Fri Dec 15, 2017 6:10 pm

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.
Last edited by sektor2111 on Fri Dec 15, 2017 6:13 pm, edited 1 time in total.

JackGriffin
Godlike
Posts: 3765
Joined: Fri Jan 14, 2011 1:53 pm
Personal rank: -Retired-

Re: fRand() range

Post by JackGriffin » Fri Dec 15, 2017 6:12 pm

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.
So long, and thanks for all the fish

Higor
Godlike
Posts: 1832
Joined: Sun Mar 04, 2012 6:47 pm

Re: fRand() range

Post by Higor » Fri Dec 15, 2017 6:56 pm

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.
ImageImage
Image unreal://23.111.157.138:7777
Image unreal://46.228.199.205:7788

User avatar
Barbie
Godlike
Posts: 2107
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: fRand() range

Post by Barbie » Sat Dec 16, 2017 10:29 am

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
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett

User avatar
sektor2111
Godlike
Posts: 5336
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: fRand() range

Post by sektor2111 » Sat Dec 16, 2017 11:00 am

If you do what I said I'll bet that you'll vaporize those errors - code can be conformed because it's server-side.
Last edited by sektor2111 on Sat Dec 16, 2017 5:48 pm, edited 1 time in total.

nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: ⚋⚊⚌☰⚞⌖⚟☰⚌⚊⚋

Re: fRand() range

Post by nogardilaref » Sat Dec 16, 2017 1:35 pm

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.

User avatar
sektor2111
Godlike
Posts: 5336
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: fRand() range

Post by sektor2111 » Sat Dec 16, 2017 5:52 pm

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

Higor
Godlike
Posts: 1832
Joined: Sun Mar 04, 2012 6:47 pm

Re: fRand() range

Post by Higor » Sat Dec 16, 2017 7:03 pm

FRand() in UT can return 1
Use Rand() or multiply like this: *4.99
ImageImage
Image unreal://23.111.157.138:7777
Image unreal://46.228.199.205:7788