Main Site Documentation

Question about mbed rand()


#1

Thought I would ask about rand();

(Partial code shown below)



 int r1 = 0;
 int r2 = 0;
 int r3 = 0;
 int r4 = 0;

void toggler() {

    r1 = (rand() % 6);
    r2 = (rand() % 6);
    r3 = (rand() % 6);
    r4 = (rand() % 50);
    
  //bar 1,2,and 3 are arrays of strings

    msg1 = bar1[r1]; 
    msg2 = bar2[r2];
    msg3 = bar3[r3];    

    serial.printf(" %d ",r4); //Test for debug added

    if(r4 == 25) {

        //I was wondering why I never got a hit!

	}	
}


I was never receiving r4 = 25 for the if statement so I added a serial.printf() to debug.

I found out that all the values returned by rand( % value) are even numbers.

Is this normal? Or do I need to do something special to receive both odd AND even values?

Terminal view of a short test run attached.

Thanks!


#2

What about r1, r2 and r3. Are they even as well?


#3

@ Architect -

Well… I have to admit I never bothered to check them… Sorry, back to check the others.

Cannot do it immediately though.


#4

I am just curious to see if odd calls produce odd numbers.


#5

@ Architect -

r1, r2, r3 are odd and even

r4 all even



void toggler() {
    r1 = (rand() % 6);
    r2 = (rand() % 6);
    r3 = (rand() % 6);
    r4 = (rand() % 50);
    
    msg1 = bar1[r1];
    msg2 = bar2[r2];
    msg3 = bar3[r3];    

    serial.printf(" %d %d %d %d\r\n",r1, r2, r3,r4);
    if(r4 == 25) {
        
        disp.drawString(DisplayN18::WIDTH / 2 - (DisplayN18::CHAR_WIDTH + DisplayN18::CHAR_SPACING) * strlen(szErase) / 2, DisplayN18::HEIGHT-DisplayN18::CHAR_HEIGHT - 78, szErase, DisplayN18::BLACK, DisplayN18::BLACK);
        disp.drawString(DisplayN18::WIDTH / 2 - (DisplayN18::CHAR_WIDTH + DisplayN18::CHAR_SPACING) * strlen(buf) / 2, DisplayN18::HEIGHT-DisplayN18::CHAR_HEIGHT - 78, buf, DisplayN18::GREEN, DisplayN18::BLACK);    
    }
}






#6

r1 and r4 are always even
r2 and r3 are always odd

I wonder if it changes if randomizer is seeded differently.


#7

@ Architect -

I’ll play around and see what happens.

Not really a issue but I had to make sure I was not nuts!

Thanks for your time…


#8

Did you seed the random number generator?

srand()

I think the example for Retro uses the ADC to do it.

If you do not seed the random number generator somewhat randomly you will get the same list of “random numbers” every time you run your program from what I understand.


#9

That’s been my experience, though even using srand, I end up with the same sequence each time. I may be doing it wrong, though. :slight_smile:


#10

It is important to seed the random number generator with a “random” number. Normally I used time() but in a desktop application or system with an OS which has a rather random program start time.

The Retro code uses the Adc input (probably from an open pin? as I have not checked).

Time is probably a bad idea for our application because the ARM chip boots up in a fixed amount of time every time (relatively the same amount of time … ms level not ns).

Maybe you should try seeding it with time when the user presses a key or if you don’t have that with a button press or something… That way you start with something random.

I found this tidbit on what might be inside the rand() function on the mbed platform:

Also you can add more randomness by swapping around the order you call the random function in with a random switch statement :smiley:

switch(rand() % 4)
{
case (0):
r1 = (rand() % 6);
r2 = (rand() % 6);
r3 = (rand() % 6);
r4 = (rand() % 50);
break;
case (1):
r1 = (rand() % 6);
r2 = (rand() % 6);
r4 = (rand() % 50);
r3 = (rand() % 6);
break;
case (2):
r1 = (rand() % 6);
r4 = (rand() % 50);
r2 = (rand() % 6);
r3 = (rand() % 6);
break;
case (3):
r4 = (rand() % 50);
r1 = (rand() % 6);
r2 = (rand() % 6);
r3 = (rand() % 6);
break;
}

Or some smarter way than I have illustrated.

But yeah I think that is very odd to get even numbers all the time. How weird. I wish Vegas was like that. Roulette anyone?


#11

@ cfavreau -

Thanks for the reply.

I’ll try your ideas.


#12

Using an ADC input is a good plan for getting a random number but realistically only the least significant few bits are going to be random.

This is the code I used on my mbuino dice program:

 
   // create a 32 bit number out of 32 LSBs from the ADC
    uint32_t seedValue = 0;
    uint16_t value;
    uint8_t counter;
 
    for (counter = 0; counter < 32; counter++) {
        seedValue = seedValue<<1;
        value = RandomIn.read_u16(); // reads a 10 bit ADC normalised to 16 bits.
        if (value & 0x0040)          // LSB of ADC output is a 1
            seedValue++;
    }
 
    srand(seedValue);     // seed the random generator with the background noise of an analog input


Once running I also had a truly random input, a person, so rather than using every random number generated I calculated a number based on the time in microseconds between two user inputs and threw that many results away each time I needed a number.
Not the most cpu efficient method but it does avoid any potential patterns in the numbers generated.

Full code it here:
http://developer.mbed.org/users/AndyA/code/mBuDice/


#13

@ AndyA - Nice! Definitely going to try your seeding method.