| View previous topic :: View next topic |
| Author |
Message |
Ghoti
Joined: 31 Dec 2005 Posts: 288
|
Posted: Sat Jan 28, 2006 8:20 am Post subject: Problem with a genuine randomizer |
|
|
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 |
|
 |
Garak
Joined: 27 Jul 2005 Posts: 46
|
Posted: Sat Jan 28, 2006 8:33 am Post subject: |
|
|
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 |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Sat Jan 28, 2006 8:56 am Post subject: |
|
|
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 |
|
 |
Jim

Joined: 02 Jul 2005 Posts: 487 Location: Sydney
|
Posted: Sat Jan 28, 2006 10:51 am Post subject: |
|
|
->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 |
|
 |
Garak
Joined: 27 Jul 2005 Posts: 46
|
Posted: Sat Jan 28, 2006 1:16 pm Post subject: |
|
|
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 |
|
 |
Saotome

Joined: 03 Apr 2004 Posts: 182
|
Posted: Sat Jan 28, 2006 7:40 pm Post subject: |
|
|
| 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 |
|
 |
Ghoti
Joined: 31 Dec 2005 Posts: 288
|
Posted: Sat Jan 28, 2006 9:18 pm Post subject: |
|
|
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 |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Sat Jan 28, 2006 11:16 pm Post subject: |
|
|
/**
* 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 |
|
 |
Ghoti
Joined: 31 Dec 2005 Posts: 288
|
|
| Back to top |
|
 |
Ghoti
Joined: 31 Dec 2005 Posts: 288
|
Posted: Tue May 23, 2006 11:34 pm Post subject: |
|
|
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 |
|
 |
Saotome

Joined: 03 Apr 2004 Posts: 182
|
Posted: Wed May 24, 2006 12:32 am Post subject: |
|
|
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 |
|
 |
Ghoti
Joined: 31 Dec 2005 Posts: 288
|
Posted: Wed May 24, 2006 12:45 am Post subject: |
|
|
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 |
|
 |
CyberBill
Joined: 26 Jul 2005 Posts: 86 Location: Redmond, WA
|
Posted: Wed May 24, 2006 7:26 am Post subject: |
|
|
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 |
|
 |
Hexstr
Joined: 23 May 2006 Posts: 5
|
Posted: Wed May 24, 2006 4:00 pm Post subject: |
|
|
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 |
|
 |
BlackDiamond
Joined: 02 Jul 2005 Posts: 16 Location: Paris, FRANCE
|
Posted: Wed May 24, 2006 5:41 pm Post subject: Re: Problem with a genuine randomizer |
|
|
| 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 |
|
 |
waterbottle
Joined: 07 Jul 2006 Posts: 3
|
Posted: Sat Aug 12, 2006 3:33 am Post subject: |
|
|
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 |
|
 |
Kojima
Joined: 26 Jun 2006 Posts: 275
|
Posted: Sat Aug 12, 2006 3:56 am Post subject: |
|
|
| 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 |
|
 |
siberianstar
Joined: 22 Jun 2006 Posts: 70
|
Posted: Sat Aug 12, 2006 4:26 am Post subject: |
|
|
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 |
|
 |
Kojima
Joined: 26 Jun 2006 Posts: 275
|
Posted: Sat Aug 12, 2006 4:35 am Post subject: |
|
|
| thanks, figured i could do it that way, just wondering if there was a fast build in func. |
|
| Back to top |
|
 |
Saotome

Joined: 03 Apr 2004 Posts: 182
|
Posted: Sat Aug 12, 2006 5:42 am Post subject: |
|
|
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 |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Sat Aug 12, 2006 7:12 am Post subject: |
|
|
| 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 |
|
 |
siberianstar
Joined: 22 Jun 2006 Posts: 70
|
Posted: Sat Aug 12, 2006 8:00 am Post subject: |
|
|
| 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 |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Sat Aug 12, 2006 8:08 am Post subject: |
|
|
| 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 |
|
 |
siberianstar
Joined: 22 Jun 2006 Posts: 70
|
Posted: Sat Aug 12, 2006 8:33 am Post subject: |
|
|
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 |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Sat Aug 12, 2006 9:50 am Post subject: |
|
|
| 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 |
|
 |
siberianstar
Joined: 22 Jun 2006 Posts: 70
|
Posted: Sat Aug 12, 2006 10:15 am Post subject: |
|
|
| yep, srand is much faster |
|
| Back to top |
|
 |
Jim

Joined: 02 Jul 2005 Posts: 487 Location: Sydney
|
Posted: Sat Aug 12, 2006 11:17 am Post subject: |
|
|
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 |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Sat Aug 12, 2006 11:23 am Post subject: |
|
|
| 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 |
|
 |
|