NXC random numbers / random seed

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC random numbers / random seed

Post by HaWe »

fine, thank you, this seems to work :)

Code: Select all

// global variable to plant the random seed
unsigned int RAND_SEED = 1;  // to be patched, e.g. by srand()


// random function, only positive values
unsigned int rand_()
{
  RAND_SEED = RAND_SEED * 1103515245 + 12345;
  return (RAND_SEED % (RAND_MAX + 1));
}


// random seed for a new random series
void srand(int seed)
{
  RAND_SEED = seed;   // just patches the global RAND_SEED variable
}

//******************************************************

task main(){
  int myRandomNumber;

  srand(1);  // or any other value, e.g. a timer counter
  while (true) {
     myRandomNumber=rand_() % 100;   // 0...99
     printf("%d",  myRandomNumber);
     Wait(1000);
  }
}
I will include this into my math.h!
:D
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC random numbers / random seed

Post by HaWe »

I'm curious if it would be probably better to use "long" instead of "int" for the rand_ argument because it multiplies by 1103515245:

Code: Select all

00038 int rand_r(unsigned int *seed)
00039 {
00040         *seed = *seed * 1103515245 + 12345;
00041         return (*seed % ((unsigned int)RAND_MAX + 1));
00042 }
edit: I assume this is for 32bit systems where they have 32bit ints, not 16bit ints=shorts what actually is what we have...

Code: Select all

unsigned long RAND_SEED = 1; 
//...
unsigned int rand_()
{
  RAND_SEED = RAND_SEED * 1103515245 + 12345;
  return (RAND_SEED % (RAND_MAX + 1));
}
gloomyandy
Posts: 323
Joined: 29 Sep 2010, 05:03

Re: NXC random numbers / random seed

Post by gloomyandy »

Yes this will be for 32bit ints does NXC really have 16 bit ints? I'm surprised as the native word size for the ARM is 32bits...
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: NXC random numbers / random seed

Post by mattallen37 »

gloomyandy wrote:Yes this will be for 32bit ints does NXC really have 16 bit ints? I'm surprised as the native word size for the ARM is 32bits...
From the HTML NXC help file
In NXC the int type is a signed 16-bit value.
Also from the same help file.
In NXC the long type is a signed 32-bit value.
So it appears that NXC supports 16 bit signed variables as "int", but there are other variable options (such as unsigned).
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC random numbers / random seed

Post by HaWe »

I wrote a litte program with which you may observe the distibution of the random numbers.
The numbers are randomized from 0...15 and their distribution is displayed on the screen over the time.
You may freeze the screen pressing any button (ExitBtn not too long!) ;)
Enjoy it!

Code: Select all

//*****************************************************************
// math.h random functions

// global variable to plant the random seed
unsigned long RAND_SEED = 1;  //  to be patched, e.g. by srand()


// random function, only positive values
unsigned int rand_()
{
  RAND_SEED = RAND_SEED * 1103515245 + 12345;
  return (RAND_SEED % (RAND_MAX + 1));
}


// random seed for a new random series
void srand(int seed)
{
  RAND_SEED = seed;   // just patches the global RAND_SEED variable
}


//*****************************************************************
// nxtio.h  string and i/o functions

#define printf1( _x, _y, _format1, _value1) { \
  string sval1 = FormatNum(_format1, _value1); \
  TextOut(_x, _y, sval1); \
}

bool btnhit(){
   return ( ButtonPressed(BTN1, false) || ButtonPressed(BTN2, false)
         || ButtonPressed(BTN3, false) || ButtonPressed(BTN4, false));
}

char LCDline[]={56,48,40,32,24,16,8,0};

//*****************************************************************

task main(){
  int myRand, ibuf, x, y;
  int RandDistr[16];
  
  SetLongAbort(1);
  
  srand(1);
  // or any other value, e.g. using a timer counter like
  srand(CurrentTick()*BatteryLevel());
  
  printf1( 0,LCDline[0],"seed=%d",RAND_SEED);
  printf1( 0,LCDline[3],"%s", "press any btn");
  while(!btnhit());
  
  ClearScreen();
  for (char i=0; i<8; i++) {
     printf1( 0,LCDline[i],"%2d",2*i);
     printf1(46,LCDline[i],"|%2d",2*i+1);
  }

  while (RandDistr[myRand]<9999) {
     myRand=rand_() % 16;   // 0...15

     RandDistr[myRand]++;
     ibuf=RandDistr[myRand];
     x=(myRand%2)*50;
     y=myRand/2;
     
     printf1(22+x,LCDline[y],"%4d",ibuf);
     
     while(btnhit()); // wait while button pressed for screen freezing
  }
  while(true);
}
Last edited by HaWe on 30 Jan 2011, 13:04, edited 6 times in total.
m-goldberg
Posts: 73
Joined: 29 Sep 2010, 12:05

Re: NXC random numbers / random seed

Post by m-goldberg »

doc-helmut wrote:But if I understand you correctly, we will get at least ALWAYS an independent series of random numbers and NEVER identical series....(?)
Yes, you will always get a different sequence of pseudo-random numbers from NXC since srand is continuously being called with the current system time. There is, I suppose, a vanishing small probability the you could get the same sequence by reseting the system clock (by turning the NXT off and then on again) but you certainly couldn't depend on it :-)
Regards, Morton
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC random numbers / random seed

Post by HaWe »

thanks a lot, Morton and Andy,
that led me to the idea to use

Code: Select all

srand( CurrentTick()*BatteryLevel() )
to be a kind of "real randomized initializaion seed" to get "real independent random sequences".
And if you want to have always identical sequences for test purposes you can use

Code: Select all

srand( 1 )
or whatever.

I changed the code above, so you may see now how the seed looks like before the randomization starts!

What do you think of that, peeps? ;)

(on the highway to ACDC... :P )
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: NXC random numbers / random seed

Post by afanofosc »

I was not clear in my email to Morton regarding how the firmware initializes the random seed - or more precisely, how the RandomNumber system call function works. The way the firmware works is that each time you ask for a random number via the RandomNumber system call it increments a counter. When that counter reaches 20 it is set back to 0. If the counter value is 0 then it calls srand before it calls rand. I could change this, of course, and make it so that you can call srand directly in a user program but I am not sure why I would want to take the time to do that. I guess if you wanted to generate the same random numbers each time you run your program then you would want to be able to control the seed and how frequently srand is called.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC random numbers / random seed

Post by HaWe »

Andy's C code random algorithm which I'm using in my code above seems to do quite that:
I can plant both constant or varying seeds to get identical or varying random sequences.
I'm not quite sure if the generated "random" sequences of Andy's code are all stochastical independend. The distribution of single drawings seems to be normal distributed, but it has to be proved that all subsequences are uniformly distributed (for n -> ∞). Maybe for a first test I once will try a Chi-square test of all 16x16 number couples if I'll find the time...
I think for the moment Andy's algorithm for "my" rand_() and srand() is a good workaround for a substitute for the Lego Firmware spoof rand function ;)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC random numbers / random seed

Post by HaWe »

just got a hint to the Mersenne-Twister "TT800": That might be an alternative random algorithm:

Code: Select all

unsigned TT800(void) {
  const int N = 25;
  const int M = 7;
  const unsigned A[2] = { 0, 0x8ebfd028 };

  static unsigned y[25];
  static int index = N+1;

  if (index >= N) {
    int k; 
    if (index > N) {
       unsigned r = 9, s = 3402;
       for (k=0 ; k<N ; ++k) {
         r = 509845221 * r + 3;
         s *= s + 1;
         y[k] = s + (r >> 10);
       }
    }
    for (k=0 ; k<N-M ; ++k)
       y[k] = y[k+M] ^ (y[k] >> 1) ^ A[y[k] & 1];
    for (; k<N ; ++k)
       y[k] = y[k+(M-N)] ^ (y[k] >> 1) ^ A[y[k] & 1];
    index = 0;
  }

  unsigned e = y[index++];
  e ^= (e << 7) & 0x2b5b2500;
  e ^= (e << 15) & 0xdb8b0000;
  e ^= (e >> 16);
  return e;
}
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest