randomint 'problem'

Report core bugs regarding the Ultima Online Emulator Core release (version 097). You can attach your Core Dump. One bug per post.

Moderator: POL Developer

Locked
phao
Grandmaster Poster
Posts: 129
Joined: Fri Aug 31, 2007 2:25 pm
Location: Brazil

randomint 'problem'

Post by phao »

i have this line of code

Code: Select all

var hair := cint(race_hair_list[randomint(race_hair_list.size()) + 1]);
and 'race_hair_list' is an array of hair ids

it seems that the randomint() is returning the same number everytime. this line of code is called everytime a character is created.

good observations:
- it isn't evertyime, just everytime for the first char created
- so the second char i'll have a diferent hair, and it is the same hair everytime.
- so it seems that for each char it is returning an 'equal' number.

is that a bug? i think it is.

i've heard about somethine like seed() (an C function), and i dont know how, it modifies the base variable the random functions use to generate random numbers, is that something like that in POL?

is that really a bug?
phao
Grandmaster Poster
Posts: 129
Joined: Fri Aug 31, 2007 2:25 pm
Location: Brazil

Post by phao »

well, sorry flood, beeing or not a bug, it's a problem to me, it seems that the randomint() returning values are 'predefined' (i doubt they really are).

i've done something to 'avoid that'.

in the start.src i have

Code: Select all

use os;

start_script("fix_random_bug", 10);
in the fix_random_bug.src i have

Code: Select all

use util;
use os;

program fix_random_bug(val)
  while(1==1)
    randomint(val);
    sleepms(500);
  endwhile
endprogram
after doing that, the results are beeing different from the 'everytime the same', each time i start the server and recreate a lot of char, i'm getting different hairs.[/code]
Xpatriat
New User
Posts: 7
Joined: Sat Aug 04, 2007 2:51 pm

Post by Xpatriat »

You are absolutely correct; The random generator in POL is likely very deterministic - meaning it probably does literally give the same series of values every time. You mentioned a 'seed'. A typical non-cryptographic random generator typically takes a 'seed' number, and then it produces an EXACT, predictable series of values based on the seed. Usually this is OK, because no one really knows when individual calls to the random function are going to be made. But POL also seems to have some issue with the values per-thread, or something similar.

I'm intrigued that your solution seems to work, though. That's actually an intuitive solution. You might also increase the 'randomness' of it by having each value modify the sleep time slightly - maybe take RandomInt(10), multiply by 10, and add the value to 450 for the sleepms time. That might add to the 'perception' of randomness of the values.


For those wondering; the reason typical 'random' generators are not really random is because a truly 'nearly-random' number is near impossible for a computer to generate - and it often takes time to do it, because it has to try to get some values from human or environmental variables over time. The best a computer can do otherwise is try to generate numbers that 'feel' random when viewed across time.
User avatar
OldnGrey
POL Expert
Posts: 657
Joined: Sat Feb 04, 2006 6:26 pm

Post by OldnGrey »

Amazing really.
I occasionally get players complaining to me about the way the dice outcomes effect them.

I had a script that simply said if ( randomint(6) == 0 ) then do something. I'd be expecting that to pass 1 in 6 times, but it's more like 1 in 30. Because changing it to test for a 1 does work around 1 in 6.

I wonder just how many of our scripts are not giving the results we expect because of random numbers?

Using things like the last 4 digits of readgameclock as a seed also appeals to me somewhat. I've put Phao's script in my shard just in case it's going to stop my players complaining, but wonder if anyone else has some thoughts on taming randomint?
Luth
Former Developer
Posts: 200
Joined: Mon Jan 30, 2006 8:10 am

Post by Luth »

Realize that Random() is NOT an even distribution of numbers. You can do RandomInt(6) ten times in a row and get six 1s, and it is still "random." In fact, if you did have guaranteed statistical evenness then it wouldn't really be random; you'd be able to predict which number would come next. Statistical probabilities are ONLY valid for sufficiently large quantities (hundreds, thousands, or millions of test cases). Anything less is nearly meaningless.

Imagine it like this: There is an infinite sequence of numbers in a list. RandomInt pulls the "next" value and returns it. If you start at the head of the list [0] every time, the sequence will be the same every time. Makes sense, right? Thats where "seeding" comes in. Setting a "seed" is like setting a position in the list to start reading numbers at. Thus you need a random / psuedo-random outside value to seed with.

Phao's fix works because there is a psuedo-random outside value (the time until a "real" randomint call is made) which results in varied previous numbers of times randomint was called, thus psuedo-seeding the random generator. He may be pulling the same sequence of numbers every time, but a random amount of those numbers are discarded before one is accepted.

From a programming point of view, OGs fix is the best; seeding the random number generator with a psuedo-random outside value (in this case, the game clock value [the bigger range the seed, the better]). Its a do-once action that will result in different random sequences (nearly) every time you use it (and it doesn't require another process to keep running ;) ).
User avatar
OldnGrey
POL Expert
Posts: 657
Joined: Sat Feb 04, 2006 6:26 pm

Post by OldnGrey »

In fact Phao's suggestion really does work.

I put it in and didn't tell most players. I am getting reports that things really do appear to be more random - in fact things are appearing at the rate the RandomInt number is suggesting. So much so that I am having to tone down the appearance of rare items in the fishing script.

The theory of how RandomInt works is useful to know, but what's more useful is to be able to just code without wondering any more.

I hope this isn't on a per thread basis, so far it seems to be okay.
Luth
Former Developer
Posts: 200
Joined: Mon Jan 30, 2006 8:10 am

Post by Luth »

I didn't say it wouldn't work; I gave reasons why it would. :) The more you can find a way to add randomness, the better.
Yukiko
Distro Developer
Posts: 2825
Joined: Thu Feb 02, 2006 1:41 pm
Location: San Antonio, Texas
Contact:

Post by Yukiko »

For some reason I seem to get a better "random" distribution when I use RandomDiceRoll() rather than RandomInt(). Not sure why. Maybe it's just my perception but I set-up a script using both and RandomDiceRoll() appeared to do better.
Luth
Former Developer
Posts: 200
Joined: Mon Jan 30, 2006 8:10 am

Post by Luth »

How many thousands of times did you test? If you only tried a couple dozen, or a couple hundred, you completely miss the usefulness of statistics. ;-)

Still, though, if someone reminds me, I'll look at the source and see if there is a code-wise difference between the two functions.

If anything is wonky, I think I'll replace the code with this:

Code: Select all

unsigned int RandomInt(unsigned int max)
{
  return 6;  //this number was selected by a dice roll and is therefore completely random
}
User avatar
OldnGrey
POL Expert
Posts: 657
Joined: Sat Feb 04, 2006 6:26 pm

Post by OldnGrey »

In the "real world" of doing scripts for our game, all we want is to throw a dice once and use the outcome. My poor suffering players are rarely comforted with things like "in the long run it's random" when they get 4 fails in a row at supposedly 50% odds.

I always get reports from players that number sequences go in bunches - ie it almost appears like the mythical losing streak. I even got a complaint last night that they were winning TOO much. sheesh.

For my latest trick I am now going to replace things like
if ( RandomInt(2) == 1 )

with
if ( RandomInt(100) < 50 )

Sounds like it will have more of a chance to 'appear' random.
User avatar
ncrsn
Grandmaster Poster
Posts: 255
Joined: Fri Feb 10, 2006 12:15 am

Post by ncrsn »

OldnGrey, if your players want predictable randomness and you are willing to give that to them, why are you sticking with random number generator so much?

I didn't test this, but I think it's worth a look.

Code: Select all

function Random( number, byref curvalue )
    
    if (curvalue == error)
        curvalue := RandomInt(number);
    else
        curvalue += 1;
    endif
    
    if (curvalue >= number - 1)
        curvalue := 0;
        return 1;
    endif
endfunction
Usage could be like this.

Code: Select all

    // Player has a 1/4 chance to get a congratulation message
    var curvalue := GetObjProperty(who, "#CongraDice");
    
    if (Random(4, curvalue))
        SendSysMessage(who, "Congratulations!");
    endif
    
    SetObjProperty(who, "#CongraDice", curvalue);
This isn't an ideal script: one would likely integrate the cprop part into (another) function to ease the use. And if repeated this isn't really random at all, so someone could find this even boring.

--

Some years ago I did test the POL's randomness using RandomInt(). I couldn't find the data anymore, so you'll have to take my word for it, but it was surprisingly random when there were 10 000, 100 000 and even million throws. Surprisingly, because I, too, had heard the "POL's random generator sucks!" lines.

I never did test the difference between RandomInt, RandomDiceValue and RandomFloat, because I always thought they were basically the same.
Luth
Former Developer
Posts: 200
Joined: Mon Jan 30, 2006 8:10 am

Post by Luth »

OG, it sounds like you want non-random returns, then. (And, thus, not a "random problem" 8)) If you want low-test statistical accuracy, then write your own function:

Create a string "Values":
"00101001100110101110"

function GetFiftyPercent() would look something like:
{
var idx := GetGlobalProp("fiftyIdx");
var val := Values[idx];
SetGlobalProp("fiftyIdx", (idx+1)%(strlen(Values));
return CInt(val);
}

This will give you pure statistical accuracy over a very small (20) trial set. If you make the string long enough that it cant be memorize, but small enough that you can ensure high statistical accuracy over a small trial set, then that should make them happy, right?

(ps: thats psuedo script, dont go copy/pasting and expecting it to work.)

(pps: If you bet on black every time, seeing five reds in a row does not mean that the randomness of physics is broken. ;-) )
Pierce
Forum Regular
Posts: 420
Joined: Thu Feb 02, 2006 8:33 am

Post by Pierce »

A few years ago i also thought of a randomint "problem or bug". Therefor i wrote a small textcmd script (.runrandom) to check it. Here the 97 code of it:

Code: Select all

use uo;
use os;
use util;

program randomstatistics( who, stopcounter )

 var counter := 0;
 var temp;
 var statisticarray := {0,0,0,0,0,0,0,0,0,0};


 while (counter != CInt(stopcounter))
  temp := RandomInt(10);
  temp += 1;
  statisticarray[temp] += 1;
  counter += 1;
  sleepms(1);
 endwhile
 SendSysMessage(who, "Statistics: " + statisticarray);  

endprogram
Sure it can also be done with other than a 10 % randomint.
If you e.g. type .runrandom 10, which means it runs 10 times, you could possibly think of a "bug".
But to get a visible view of what Luth means, just try .runrandom 100000.
Nearly all values are around 10.000 this time, which is a good statistical outcome :D Surely they are not exact 10.000 cause its random :grin:
Locked