Spot the Bug?  Not so random numbers.

Hi folks --

I have a little piece of code that's driving me bats. On each loop the current value of mode should change randomly to anything other than its current value. However, I find this code only works most of the time and I do get duplicates.

I originally did not cast the mode/oldMode values to int, but added that since I thought the longs might be read as different by the chip when I saw them as not.

Does anyone see what I'm missing?

void diag() {
  oldMode = mode;
  do {
    mode=random(0,5);
  } while(int(oldMode)==int(mode));
  Serial.print("Mode: ");
  Serial.print(mode);
  Serial.print(" Old Mode: ");
  Serial.print(oldMode);
  delay(1000);
}

There is random, and there is random.

Or, more correctly, there is more pseudo-random.

On most modern computers a series of random numbers is actually a long series of numbers that is different only for different seeds. See the random() docs:

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.

Conversely, it can occasionally be useful to use pseudo-random sequences that repeat exactly. This can be accomplished by calling randomSeed() with a fixed number, before starting the random sequence.

There is a whole science of increasing the apparent randomness for pseudo-random numbers generating by computers. For cryptography it can be very important to generate strong random sequences.

In the code you show here all we see is the call to random(). This implies that the same series of numbers could be fetched over and over again.

True -- I'm very familiar with the pseudo-random nature of the numbers, but that is not the problem. The problem is not that the numbers are not random enough, but that the code exits the do-while loop SOMETIMES when both the current and previous values of the numbers are the same.

What should happen is that as long as my new value and old value are the same the code should generate another random number. Only when the values differ from one another should the loop exit.

Here's the plain english version of the code:

  1. Set "old value" to equal the current value.
  2. Generate a random number and store it as the current value.
  3. If the current value is the same as the old value try again (i.e.: go back to step #2). Otherwise, the new value is acceptable.

Most of the time it does exactly what I expect. Periodically, though, it fails. I can't figure out why...

How are mode and oldMode declared?

  • Brian

Both are declared as long since that's what random returns.

I've tried a variety of casts to int before testing, but no joy there either.

I think I'm going to try declaring them as integers and then set mode using

mode = int(random(0,5));

I've still been wondering if somewhere what I see and what the chip sees aren't a little different -- which could definitely cause the comparison to pass when it shouldn't.

I ran your code for a couple thousand iterations and didn't see any repeats:

long oldMode, mode;

void setup()                    // run once, when the sketch starts
{
  Serial.begin(19200);
  for (int i=0; i < 1000; i++) {
    oldMode = mode;
    do {
      mode=random(0,5);
    } 
    while(int(oldMode)==int(mode));
    Serial.print("Mode: ");
    Serial.print(mode);
    Serial.print(" Old Mode: ");
    Serial.print(oldMode);
    if (mode == oldMode) {
      Serial.println(" ******");
    } 
    else {
      Serial.println(" ");
    }
    delay(30);
  }

You do have oldMode declared in the global context, right?

Thanks! Yes, the variables are declared globally. This is getting more mysterious to me.

I'll try running your copy of the code via copy/paste. If I still see duplicates I suspect I could be looking at strange hardware behavior. Although the board resets whenever I reload code, it hasn't been power-cycled in weeks... hmm...

Add code in setup that shows "for sure" when the Arduino reloads?

THANKS EVERYONE!

What a great community this is...

I haven't found the error, but I've found the "why". The problem lies elsewhere in the program -- turns out my main loop() is going places other than just the one function I expected. Variables get changed then sent back to the correct function. Time for a little Friday night debugging!

If you don't want repeats, use XOR.