forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Problem with a genuine randomizer

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
Ghoti



Joined: 31 Dec 2005
Posts: 288

PostPosted: Sat Jan 28, 2006 8:20 am    Post subject: Problem with a genuine randomizer Reply with quote

Hi folks,

i now use this code to random get some numbers:

Code:
// generates random number
int get_random(int lo, int hi)
{
    return (rand() % (hi-lo+1)) + lo ;
}


but this does not randomize anything... I tested my beginning of my game several times and it occured to me that i played it the same over and over again so i looked why and i saw that everytime i played the game the randomizer gave the same numbers in order everytime so i could predict the outcome of it. Why is this? is there something wrong with the code? is there better code for this?

any comments are welcome.
_________________
My PSP games:

Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Back to top
View user's profile Send private message
Garak



Joined: 27 Jul 2005
Posts: 46

PostPosted: Sat Jan 28, 2006 8:33 am    Post subject: Reply with quote

Hi,

There is probably a better solution than this, but alas this is the solution I used and it did/does work.

I created the following function:

void InitRandomNumberGen()
{
int x;
struct timeval cTime;
gettimeofday(&cTime, 0);
int seed = cTime.tv_sec % 256;
for (x=0; x < seed; x++)
rand();
}

Call this function 1 time near the start of your program. It will get the system times and modulo it to get a number between 0 and 255. Then it calls the random number generator that many times. This will ensure the first random number actually used in your program is not the same random number allways returned first by the rand() function.

As you probably figured out, the random number generator allways produces the same random numbers. Doesn't sound very random but that's the way it usually works. I think normally a seed function that uses the system time (such as the one I mention above) is included in the random number function. I was suprised the one in the PSP lib did not plant a seed based on system time for you. But if you do it yourself as described above, you will get the results you are looking for.


Garak
Back to top
View user's profile Send private message Send e-mail AIM Address
Raphael



Joined: 17 Jan 2006
Posts: 646
Location: Germany

PostPosted: Sat Jan 28, 2006 8:56 am    Post subject: Reply with quote

include <psputils.h> in your program and try the following

SceKernelUtilsMt19937Context ctx;
sceKernelUtilsMt19937Init(&ctx, time(NULL));

u32 rand_val = sceKernelUtilsMt19937UInt(&ctx);

the last statement should give you a random number everytime.
Back to top
View user's profile Send private message Visit poster's website
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sat Jan 28, 2006 10:51 am    Post subject: Reply with quote

->Garak. That will give 256 different start points, which is better, but not as good as calling
srand(time(NULL));
which gives RAND_MAX+1 starting points.
Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
Garak



Joined: 27 Jul 2005
Posts: 46

PostPosted: Sat Jan 28, 2006 1:16 pm    Post subject: Reply with quote

srand(time(NULL)),

Yea that's hot... that's hot. I'll be sure to update my code and use it. Thanks.

Garak
Back to top
View user's profile Send private message Send e-mail AIM Address
Saotome



Joined: 03 Apr 2004
Posts: 182

PostPosted: Sat Jan 28, 2006 7:40 pm    Post subject: Reply with quote

Raphael wrote:
...
SceKernelUtilsMt19937Context ctx;
sceKernelUtilsMt19937Init(&ctx, time(NULL));

u32 rand_val = sceKernelUtilsMt19937UInt(&ctx);
...

Thats even hotter, Garak ;) (Mt19937 = Mersenne twister)
It gives "better" random numbers, and it's faster (should be - didn't test on PSP - but my PS2 version is).
_________________
infj
Back to top
View user's profile Send private message
Ghoti



Joined: 31 Dec 2005
Posts: 288

PostPosted: Sat Jan 28, 2006 9:18 pm    Post subject: Reply with quote

Hi folks,

If i am correct the function Raphael gave me was the best one right?
So it gives a number between? i mean i only have to get a 1 or a 2 randomized. like a boolean value :)
_________________
My PSP games:

Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Back to top
View user's profile Send private message
Raphael



Joined: 17 Jan 2006
Posts: 646
Location: Germany

PostPosted: Sat Jan 28, 2006 11:16 pm    Post subject: Reply with quote

/**
* Function to return a new psuedo random number.
*
* @param ctx - Pointer to a pre-initialised context.
* @return A pseudo random number (between 0 and MAX_INT).
*/
u32 sceKernelUtilsMt19937UInt(SceKernelUtilsMt19937Context *ctx);

So the function returns a complete random value inside the u32 valuespace.
So you could just use your get_random function and replace the rand() with the mersenne twister function and it would work perfectly. Just make the context global and initialise it at the start of your program.
Or in your special case, you'd just append

rand_val = 1 + rand_val % 2;

to my code snippet.
Back to top
View user's profile Send private message Visit poster's website
Ghoti



Joined: 31 Dec 2005
Posts: 288

PostPosted: Sun Jan 29, 2006 7:57 am    Post subject: Reply with quote

Hi,

Thanks that did the trick :) now my items come out all randomized and nice :)thank you!
_________________
My PSP games:

Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Back to top
View user's profile Send private message
Ghoti



Joined: 31 Dec 2005
Posts: 288

PostPosted: Tue May 23, 2006 11:34 pm    Post subject: Reply with quote

Hi folks,

i use:

Code:
   SceKernelUtilsMt19937Context ctx;

   int RandomInit(void) {
      sceKernelUtilsMt19937Init(&ctx, time(NULL));
      return 0;
   }


// generates random number
   int get_random(int lo, int hi)
   {
      u32 rand_val = sceKernelUtilsMt19937UInt(&ctx);
      rand_val = 1 + rand_val % 2;
      return (int)rand_val;
   }


however rand_val is always empty :S i have sprintf the randval with %i to an char array and displayed it on screen but it was always empty. So according to that it didn't work.
however i use it in my program and for my blocks the randomness works, however when i output the get_random to a char array and display it also the ones that work on my blocks don't show anything. How can this be?
_________________
My PSP games:

Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Back to top
View user's profile Send private message
Saotome



Joined: 03 Apr 2004
Posts: 182

PostPosted: Wed May 24, 2006 12:32 am    Post subject: Reply with quote

what does empty mean?

your function:
Code:

int get_random(int lo, int hi)
   {
      u32 rand_val = sceKernelUtilsMt19937UInt(&ctx);
      rand_val = 1 + rand_val % 2;
      return (int)rand_val;
   }

generates only "1" or "2", so depends on how you're displaying them on the screen.
But I guess you won't see very much with something like a printf.
_________________
infj
Back to top
View user's profile Send private message
Ghoti



Joined: 31 Dec 2005
Posts: 288

PostPosted: Wed May 24, 2006 12:45 am    Post subject: Reply with quote

Well i do this to draw:
Code:
int get_random(int lo, int hi)
   {
      u32 rand_val = sceKernelUtilsMt19937UInt(&ctx);
      rand_val = 1 + rand_val % 2;
      sprintf(sBuffer, "%i", rand_val);
      drawText(sBuffer);
      return (int)rand_val;
   }


you are right that it only gives the number between 1 en 2 but the returned value or the rand_val inside the function(see above) doesn't seem to hold any information i can use or store in an integer, what am i seeing wrong?
_________________
My PSP games:

Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Back to top
View user's profile Send private message
CyberBill



Joined: 26 Jul 2005
Posts: 86
Location: Redmond, WA

PostPosted: Wed May 24, 2006 7:26 am    Post subject: Reply with quote

You need to be a little more specific with the way you're drawing text & what sBuffer is.

Please post the code that calls the get_random() function and we can help you figure out whats wrong, because the get_random() function looks correct to me.
Back to top
View user's profile Send private message AIM Address MSN Messenger
Hexstr



Joined: 23 May 2006
Posts: 5

PostPosted: Wed May 24, 2006 4:00 pm    Post subject: Reply with quote

Hrmm, well I guess the get_random function is correct but if you are going to use it like it is defined you may want to replace the 1 and 2 with lo and hi. Like this
Code:
rand_val = lo + rand_val % hi;

Then you can just call the get_random function and pass it 1 and 2 as parameters.

Also it may not work if your context variable is not initialized. Make sure it is being initialized before the get_random function call.
_________________
Check out www.sf.net/projects/psp-tools
Back to top
View user's profile Send private message AIM Address
BlackDiamond



Joined: 02 Jul 2005
Posts: 16
Location: Paris, FRANCE

PostPosted: Wed May 24, 2006 5:41 pm    Post subject: Re: Problem with a genuine randomizer Reply with quote

Ghoti wrote:
Hi folks,

i now use this code to random get some numbers:

Code:
// generates random number
int get_random(int lo, int hi)
{
    return (rand() % (hi-lo+1)) + lo ;
}


but this does not randomize anything... I tested my beginning of my game several times and it occured to me that i played it the same over and over again so i looked why and i saw that everytime i played the game the randomizer gave the same numbers in order everytime so i could predict the outcome of it. Why is this? is there something wrong with the code? is there better code for this?

any comments are welcome.

seems you haven't initialized the generator
you have to use srand() somewhere to initialize it.

Something like that in your app should work:
Code:
int main ()
{
  /* initialize random generator */
  srand ( time(NULL) );

  /* the rest of your code here */
 ...
Back to top
View user's profile Send private message
waterbottle



Joined: 07 Jul 2006
Posts: 3

PostPosted: Sat Aug 12, 2006 3:33 am    Post subject: Reply with quote

what include is needed to use time(NULL);?

I get the error

./main.cpp: In function 'int main(int, char**)':
./main.cpp:101: error: 'time' was not declared in this scope

when I use it..
Back to top
View user's profile Send private message
Kojima



Joined: 26 Jun 2006
Posts: 275

PostPosted: Sat Aug 12, 2006 3:56 am    Post subject: Reply with quote

Is there a floating point random number generator in the psp sdk? (you know like on windows, where it returns between 0 and 1 and you just scale it into range yourself)
Back to top
View user's profile Send private message
siberianstar



Joined: 22 Jun 2006
Posts: 70

PostPosted: Sat Aug 12, 2006 4:26 am    Post subject: Reply with quote

dunno if there is one in the sdk,

float __randf()
{
const int max = 1024;
return (float)(rand()%max)/max;
}

very simple,
note that i've wrote it here and i didn't try it.
Back to top
View user's profile Send private message
Kojima



Joined: 26 Jun 2006
Posts: 275

PostPosted: Sat Aug 12, 2006 4:35 am    Post subject: Reply with quote

thanks, figured i could do it that way, just wondering if there was a fast build in func.
Back to top
View user's profile Send private message
Saotome



Joined: 03 Apr 2004
Posts: 182

PostPosted: Sat Aug 12, 2006 5:42 am    Post subject: Reply with quote

you can do it like this
Code:

float x;
*(int*)&x = (rand() & 0x7FFFFF) | 0x3F800000;

you get a floating point number between 1.0 and 2.0 so if you need 0.0 to 1.0 you just need to subtract 1.0

this should be faster than the one with the slow division instructions ;)
return (float)(rand()%max)/max;
_________________
infj
Back to top
View user's profile Send private message
Raphael



Joined: 17 Jan 2006
Posts: 646
Location: Germany

PostPosted: Sat Aug 12, 2006 7:12 am    Post subject: Reply with quote

Saotome wrote:
you can do it like this
Code:

float x;
*(int*)&x = (rand() & 0x7FFFFF) | 0x3F800000;

you get a floating point number between 1.0 and 2.0 so if you need 0.0 to 1.0 you just need to subtract 1.0

this should be faster than the one with the slow division instructions ;)
return (float)(rand()%max)/max;


Nice trick :) I'll note that down in my hacky-speedy-coding-tricks note for sure. Thanks
_________________
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
Back to top
View user's profile Send private message Visit poster's website
siberianstar



Joined: 22 Jun 2006
Posts: 70

PostPosted: Sat Aug 12, 2006 8:00 am    Post subject: Reply with quote

Code:
float __randf()
{
 int x = ((((rand() << 8) & 0x7FFFFF) | 0x3F800000));
 float r;
 asm volatile(
   "move %0, %1\n" : "=e" (r) : "e" (x));
 return r;
}


this should work.

I've made a speed test using:

Code:
inline float __randf_1()
{
const int max = 1024;
return (float)(rand()%max)/max;
}

inline float __randf_2()
{
 int x = ((((rand() << 8) & 0x7FFFFF) | 0x3F800000));
 float r;
 asm volatile(
   "move %0, %1\n" : "=e" (r) : "e" (x));
 return r;
}


using a loop of 50000 cycles,
__randf_1 = 9ms
__randf_2 = 8ms
Back to top
View user's profile Send private message
Raphael



Joined: 17 Jan 2006
Posts: 646
Location: Germany

PostPosted: Sat Aug 12, 2006 8:08 am    Post subject: Reply with quote

siberianstar wrote:
Code:
float __randf()
{
 int x = ((((rand() << 8) & 0x7FFFFF) | 0x3F800000));
 float r;
 asm volatile(
   "move %0, %1\n" : "=e" (r) : "e" (x));
 return r;
}


this should work.

I've made a speed test using:

Code:
inline float __randf_1()
{
const int max = 1024;
return (float)(rand()%max)/max;
}

inline float __randf_2()
{
 int x = ((((rand() << 8) & 0x7FFFFF) | 0x3F800000));
 float r;
 asm volatile(
   "move %0, %1\n" : "=e" (r) : "e" (x));
 return r;
}


using a loop of 50000 cycles,
__randf_1 = 9ms
__randf_2 = 8ms


Now please also bench with the Mersenne Twister ;P
_________________
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
Back to top
View user's profile Send private message Visit poster's website
siberianstar



Joined: 22 Jun 2006
Posts: 70

PostPosted: Sat Aug 12, 2006 8:33 am    Post subject: Reply with quote

using Mersenne Twister for __randf_1, __randf2:

Code:

inline float __randf_1()
{
const int max = 1024;
return (float)(sceKernelUtilsMt19937UInt(&ctx)%max)/max;
}

inline float __randf_2()
{
 int x = ((((sceKernelUtilsMt19937UInt(&ctx) << 8) & 0x7FFFFF) | 0x3F800000));
 float r;
 asm volatile(
   "move %0, %1\n" : "=e" (r) : "e" (x));
 return r;
}



__randf_1 = 42ms
__randf_2 = 40ms
Back to top
View user's profile Send private message
Raphael



Joined: 17 Jan 2006
Posts: 646
Location: Germany

PostPosted: Sat Aug 12, 2006 9:50 am    Post subject: Reply with quote

siberianstar wrote:
using Mersenne Twister for __randf_1, __randf2:

__randf_1 = 42ms
__randf_2 = 40ms


Du'h that's surprising, thought it wouldn't be that much slower.
_________________
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
Back to top
View user's profile Send private message Visit poster's website
siberianstar



Joined: 22 Jun 2006
Posts: 70

PostPosted: Sat Aug 12, 2006 10:15 am    Post subject: Reply with quote

yep, srand is much faster
Back to top
View user's profile Send private message
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sat Aug 12, 2006 11:17 am    Post subject: Reply with quote

Every 624 calls to mtrand, it has to go off and update the RNG's state, which is 624 32bit integers. The code for doing a single mtrandom number is normally just a handful of xors, shifts and ands.

The C99 standard recommends this implementation for rand()
Code:

static unsigned long int next = 1;
int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}

which is just one mul, one shift, one add and one and. Many C runtimes use this exact algorithm.

So what you'll find is mtrand performance will be 'lumpy' compared with rand. Do you really need mtrand? You'd traditionally want that only if you were doing specific statistical analysis.

Jim
_________________
http://www.dbfinteractive.com


Last edited by Jim on Sat Aug 12, 2006 11:24 am; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
Raphael



Joined: 17 Jan 2006
Posts: 646
Location: Germany

PostPosted: Sat Aug 12, 2006 11:23 am    Post subject: Reply with quote

Jim wrote:
Every 624 calls to mtrand, it has to go off and update the rng's state, which is 624 32bit integers. The code for doing a single mtrandom number is normally just a handful of xors, shifts and ands.

The C99 standard recommends this implementation for rand()
Code:

static unsigned long int next = 1;
int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}


which is just one mul, one shift and one and. Many C runtimes use this exactly algorithm.

So what you'll find is mtrand performance will be 'lumpy' compared with rand. Do you really need mtrand? You'd traditionally want that only if you were doing specific statistical analysys.

Jim

Reasonable. I doubt that this implementation has a near-equal distribution over the int range (won't prove that mathematically though here :P). So if you use it for something where every random number should have same probability, it's bad (dice anyone?).
_________________
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group