Using Random()

Greetings,

I have a program that has that controls 5 LEDs. For a visual:

5
3 4
1 2

I believe I can program the code to get these 4 sequences working:

A. 1, 4, 5, 2, 3, 5
B. 1 & 2, 3 & 4, 5
C. 2, 3, 5, 1, 4, 5
D. 5, 4, 1, 5, 3, 2

What I wanted was a random number 1,2,3, or 4 (A, B, C, or D) to control which sequence order would be used.

Not being familiar with Random() I read everything I could and programmed this code:

long randNumber;

void setup(){
Serial.begin(9600);
randomSeed(analogRead(0)); // nothing connected to 0 so read sees noise
}

void loop(){
randNumber = random(1,5); // generate random number between 1 & 5
Serial.println(randNumber); // show the value in Serial Monitor

delay(1000); // wait 1 second before displaying the next number
}

I was expecting random numbers to show up, however, this is what was printed out:

3
3
2
1
4
1
4
3
2
2
4
1

If I understood everything I read, using the read of the serial port should have given me really random numbers between my min and max values. However, the output wasn't really random since I received 3 followed by 3 and later 2 followed by 2. I would not have expected these results.

So the question is how do I really get random numbers? Is my programming wrong? Basically every time I run the sketch I want the 4 numbers to be generated in a different order.

Thanks for your help!

  randNumber = random(1,5); // generate random number between 1 & 5

When the comment and the code do not agree, the comment is wrong. Every time.

I was expecting random numbers to show up, however, this is what was printed out:

What do you think is wrong with that?

However, the output wasn't really random since I received 3 followed by 3 and later 2 followed by 2. I would not have expected these results.

So, clearly your expectations are wrong. There is nothing that says the random number generator can't generate the same number two or three times in a row, any more than there is a law that says you can't roll the same value on a die more than once. Expecting otherwise is unreasonable.

Basically every time I run the sketch I want the 4 numbers to be generated in a different order.

What you need is a decent method of seeding the random number generator. Reading an unconnected analog pin isn't a decent method.

PaulS:

However, the output wasn't really random since I received 3 followed by 3 and later 2 followed by 2. I would not have expected these results.

So, clearly your expectations are wrong. There is nothing that says the random number generator can't generate the same number two or three times in a row, any more than there is a law that says you can't roll the same value on a die more than once. Expecting otherwise is unreasonable.

Indeed one of the markers for truly random number sequences is that repeats of the same number (as well as repeats of series of numbers) will occur with a predictable frequency.

Perhaps the OP wasn't looking for a random number, but rather a random card draw--like drawing a card from a single deck so that no card repeats. If so there are several good examples of how to implement that in the Playground.

http://playground.arduino.cc/Main/RandomHat

In a sequence of random numbers 1,2,3,4 you would expect that the next random number is the same as the previous one 1 in 4 times or 25%. In your sample data there are 11 opportunities and 2 duplicates. This is close to the expected 11/4 duplicates.

If your constraint is that no two adjacent numbers in the sequence are the same, randomly choose from the three remaining choices each time.

I think something as simple as remembering the last random number generated and keep generating random numbers until it doesn't match.

Something like:

byte randNumber; // if your random number constraint is 1 through 5, why do you need 4 bytes? One will do.
byte prevRand = 0; // Could be initialized as anything outside the constraints of the desired random number

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0)); // Probably not the best random seed, but it is what is suggested in the Arduino reference
}

void loop()
{
  do
  {
    randNumber = random(1,6); // generate random number between 1 & 5 (minimum is inclusive, maximum is exclusive)
  } while (randNumber != prevRand);
  prevRand = randNumber;
  Serial.println(randNumber); // show the value in Serial Monitor

  delay(1000); // wait 1 second before displaying the next number
}

Please note that I haven't test compiled or run the above. I hope I didn't introduce any syntax issues... :wink:

Also note, this only prevents single number repeats, not sequence repeats.

the problem with this loop

do
  {
    randNumber = random(1,6); // generate random number between 1 & 5 (minimum is inclusive, maximum is exclusive)
  } while (randNumber != prevRand);

is that it is

  • undefined how long it will take (in theory a deadlock) especially if the range is small

in practice it will work

wanderson:

PaulS:

However, the output wasn't really random since I received 3 followed by 3 and later 2 followed by 2. I would not have expected these results.

So, clearly your expectations are wrong. There is nothing that says the random number generator can't generate the same number two or three times in a row, any more than there is a law that says you can't roll the same value on a die more than once. Expecting otherwise is unreasonable.

Indeed one of the markers for truly random number sequences is that repeats of the same number (as well as repeats of series of numbers) will occur with a predictable frequency.

Perhaps the OP wasn't looking for a random number, but rather a random card draw--like drawing a card from a single deck so that no card repeats. If so there are several good examples of how to implement that in the Playground.

Arduino Playground - RandomHat
The following example demonstrates how to produce the numbers 1 to X in a random order, where each number only appears once, and that all numbers are produced. · GitHub

Thanks for your help! The other replies taught be about the generator, however, your post gave me something to use. Thank You!

robtillaart:
the problem with this loop

do

{
    randNumber = random(1,6); // generate random number between 1 & 5 (minimum is inclusive, maximum is exclusive)
  } while (randNumber != prevRand);



is that it is 
- undefined how long it will take (in theory a deadlock) especially if the range is small

in practice it will work

True. I suppose a slightly different approach to avoid potential multiple loops would be:

byte randNumber;
byte prevNumb = 1; // make sure this value is within the random range.

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0)); // Probably not the best random seed, but it is what is suggested in the Arduino reference
}

void loop()
{
  randNumber = random(1,5); // generate random number between 1 & 4 (minimum is inclusive, maximum is exclusive)
  if (randNumber >= prevRand) randNumber++; // corrects for values equal to the previous value,
              //and shifts values greater than previous values up by one to get a generated range
              // of 1 to 5 excluding the last generated value
  prevRand = randNumber;
  Serial.println(randNumber); // show the value in Serial Monitor

  delay(1000); // wait 1 second before displaying the next number
}

Again not compiled to check for syntax errors...

but

randNumber = random(1,5); // generate random number between 1 & 4 (minimum is inclusive, maximum is exclusive)
  if (randNumber >= prevRand) randNumber++; // corrects for values equal to the previous value,
              //and shifts values greater than previous values up by one to get a generated range
              // of 1 to 5 excluding the last generated value
  prevRand = randNumber;

if the prevRand is 4 and randNumber too, randNumber will be 5 and therefor out of range !!!
you should correct for that.
Furthermore this method will generate "predictable" pairs e.g. after a 1 there are twice as many 2's as statistically expected.

This code will never generate the same random number. If there is a "collision" with the previous value an offset is added. Then the offset is changed so that no predictable pairs come up (unless the range is only 2 as in example below) . As the code has no loops it has a predictable execution time [range].

int prevValue = -1;
int x = 0;
int y = 0;
long count = 0;
 
void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");
}

void loop() 
{
  x = getRandomNoDuplicate(1, 3);  //  gives "random" 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2 (very predicatable!!
  if (x == y) Serial.println("...");
  y = x;
  count++;
  if (count % 1000 == 0) Serial.println("M");
}

int getRandomNoDuplicate(int lower, int upper)
{
  static int offset = 0;
  int randNumber = random(lower, upper);
  if (prevValue == randNumber)
  {
    offset++;
    if (offset >= upper - lower) offset = 1;
    randNumber += offset;
    if (randNumber >= upper) randNumber = lower + randNumber - upper;
  }
  prevValue = randNumber;
  return randNumber;
}

robtillaart:
but

randNumber = random(1,5); // generate random number between 1 & 4 (minimum is inclusive, maximum is exclusive)

if (randNumber >= prevRand) randNumber++; // corrects for values equal to the previous value,
             //and shifts values greater than previous values up by one to get a generated range
             // of 1 to 5 excluding the last generated value
 prevRand = randNumber;




if the prevRand is 4 and randNumber too, randNumber will be 5 and therefor out of range !!!

Except that the stated range from the OP is 1 through 5 inclusive.

you should correct for that.
Furthermore this method will generate “predictable” pairs e.g. after a 1 there are twice as many 2’s as statistically expected.

There is a reason why it’s called pseudorandom…

This code will never generate the same random number. If there is a “collision” with the previous value an offset is added. Then the offset is changed so that no predictable pairs come up (unless the range is only 2 as in example below) . As the code has no loops it has a predictable execution time [range].

int prevValue = -1;

int x = 0;
int y = 0;
long count = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println("Start ");
}

void loop()
{
  x = getRandomNoDuplicate(1, 3);  //  gives “random” 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2 (very predicatable!!
  if (x == y) Serial.println("…");
  y = x;
  count++;
  if (count % 1000 == 0) Serial.println(“M”);
}

int getRandomNoDuplicate(int lower, int upper)
{
  static int offset = 0;
  int randNumber = random(lower, upper);
  if (prevValue == randNumber)
  {
    offset++;
    if (offset >= upper - lower) offset = 1;
    randNumber += offset;
    if (randNumber >= upper) randNumber = lower + randNumber - upper;
  }
  prevValue = randNumber;
  return randNumber;
}

Looks good to me. I’d have to take some time (which I don’t have at the moment) to fully study it, but I feel that there is still a possibility of duplicates for some values of offset on some ranges due to rollover effects. I could be wrong though.

Looks good to me. I'd have to take some time (which I don't have at the moment) to fully study it, but I feel that there is still a possibility of duplicates for some values of offset on some ranges due to rollover effects. I could be wrong though.

That's why I added a whole script, it prints three dots if there is a double value.
And every 1000 random numbers it prints an M (roman number 1000)

Ran quite some time without flaws doubles and even the minimal range worked.
Although simulation is not a guarantee for bug free-ness of code I am quite confident this code works well

  • not tested for range where maxint is upper border.

What you need is a decent method of seeding the random number generator. Reading an unconnected analog pin isn’t a decent method.

And yet I find from the “random()” reference page random() - Arduino Reference

  // if analog input pin 0 is unconnected, random analog
  // noise will cause the call to randomSeed() to generate
  // different seed numbers each time the sketch runs.
  // randomSeed() will then shuffle the random function.
  randomSeed(analogRead(0));
}

What am I missing, call me confused.

flagtrax:
What am I missing, call me confused.

Will it make you feel better?

OK - you're confused.

Why did you feel it necessary to resurrect a dive year old thread?

@AWOL

dive year old thread?

If you meant five year old...I really didn't know there was an issue with that. Please let me know if that is outside protocol. I came across the thread while looking for information on the subject of random number generation. I was seeking clarification because I thought I remembered the example in the reference section. If I ruffled feathers I'm sorry. I'm just trying to learn like everyone else. What I saw as contradictory may simply be my misunderstanding, I was trying to find that out.

A single analogRead is possibly better than nothing, but there have been plenty of discussions on this.
I don’t often use the RNG, but if I did, I’d be inclined to seed it with 32 LSBs of consecutive analogReads, packed into a single 32 bit value.

Thanks AWOL, I'm still a bit confused though, I get what you're saying and I'm trying to reconcile it with the paragraph in the reference section that says.

If it is important for a sequence of values generated by random() to differ, on subsequent executions of a sketch, use randomSeed() to initialize the random number generator with a fairly random input, such as analogRead() on an unconnected pin.

Are you saying that then is not exactly prefered? Thanks again.

The first part of the statement is true. The part about seeding the RNG with the result of analogRead() on an unconnected pin is nonsense. The result of such a read is anything but random.