gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Basic Random Number Generation

#4363 - Archeious - Fri Mar 28, 2003 10:42 pm

How can I generate simple random numbers. It doesn't have to be very good.

#4371 - fezz1k - Sat Mar 29, 2003 1:01 am

RNG

#4372 - darkcloud - Sat Mar 29, 2003 1:25 am

Here's a simple one :

Code:

unsigned int seed = 289301;

unsigned int rand()
{
    seed = 69069 * seed + 1;
    return seed >> 16;
}

_________________
Maybe in order to understand mankind, we have to look at the word itself: "Mankind". Basically, it's made up of two separate words - "mank" and "ind". What do these words mean ? It's a mystery, and that's why so is mankind.

#4576 - Indecisive - Thu Apr 03, 2003 7:48 pm

If you just want something really basic. You can just:

#include "stdlib.h"

Then, to generate a value between 0 and X you use:

rand()%X

I think I remembered that right. I'm no expert.

#4588 - tepples - Thu Apr 03, 2003 9:53 pm

Indecisive wrote:
rand()%X

BAD BAD BAD.

  • The % operation is division, which is very slow on the GBA.
  • The % operation emphasizes the low-order bits, and the low-order bits of the result of rand() in common implementations of the C standard library tend to be very predictable.
  • The rand() of newlib is slow.

The fast way to generate small random numbers is to use a linear congruential generator like the one darkcloud gave above, along with a rescaler to provide random numbers in a range. But don't call your function "rand()" because for one thing, there's already a stdlib function by that name and for another, your code does not know the value of RAND_MAX in stdlib.h (is it 2<<15? is it 2<<16? is it 2<<31? is it 2<<32?).
Code:

#define AYN_BITS 15
#define AYN_MAX (1 << AYN_BITS)

static unsigned long seed;

/* ayn() *****
   Random number generator based on one from
   http://random.mat.sbg.ac.at/~charly/server/node3.html
*/
unsigned int ayn(Player *p)
{
  seed = seed * 2147001325 + 715136305;
  return (seed >> 17) & AYN_MAX;
}

/* aynlt() *****
   Generate a random whole number less than n.
*/
unsigned int aynlt(unsigned int n)
{
  return (ayn() * n) >> AYN_BITS;
}

EDIT: Indecisive, apology accepted.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Fri Apr 04, 2003 12:53 am; edited 1 time in total

#4590 - Indecisive - Thu Apr 03, 2003 11:30 pm

I said it was really basic but apologies for not mentioning the badness, it was meant to be implied.

#4608 - Lord Graga - Fri Apr 04, 2003 10:25 am

That method CAN be OK some times...but there is another problems:

It won't work too well in some cases....I used that method in my GBAX compo entry, Klan Wars. When the AI was gong to set up their troops on the board, I had to do a y = GetRand(10). However, since 10 is a straight number (divideable by 2), then It would never set any characters up at 1, 3, 5, 7 and 9.

Ways it can be solved, but it still won't be random:

* In every set up frame do RAND()%13 (13 is a prime number) RAND()%17 times.

kinda like:
for(i=0;i<RAND()%13;i++) misc = RAND()%17;

#4610 - sgeos - Fri Apr 04, 2003 4:16 pm

Lord Graga wrote:
When the AI was gong to set up their troops on the board, I had to do a y = GetRand(10). However, since 10 is a straight number (divideable by 2), then It would never set any characters up at 1, 3, 5, 7 and 9.


This is because your seed is odd. When you multiply an odd number by another odd number, the result is always odd. If you have an even seed, your results will always be even. The low order bits are less random, so, try something like this:

seed *= 69069;
return seed ^ (seed >> 16);

OR

seed *= 69069;
seed += 1;
return seed; /* or add ^ (seed >> 16) */

I've not tested the period of the later. In either case, the period will probably be long enough for a game.

-Brendan

#4611 - sgeos - Fri Apr 04, 2003 5:03 pm

I just tested this code and it works:

unsigned long seed;

signed long dice(signed long min, signed long max)
{
seed *= 69069;
return min + ((max - min + 1) * (seed >> 16)) / 0x10000;
}

If you want a number from -20 to 90, call:
dice(-20, 90);

Note that (max - min + 1) can be no more than 16 bits or else the code will break. You can call something like:
dice(16000, 80000);

Because (max - min + 1) is less than 16 bits (64001), even though max is greater than 16 bits. As far as big ranges with negative numers go, I don't know what the largest, or smallest depending on how you look at it,
value for (max - min + 1). I imagine that if it fits in 16bits everything should be ok.

-Brendan