Odd behavior with Random

If you do an analogRead() on A0 do you get a steady value or does it vary ? Have you got anything connected to A0 ?

With a floating A0 I get 0 more than 6 times in a row with the original code.

Hi,

Nothing connected to A0. analogRead varies a little--values clustered around 314, tending to become more stable over time.

--Michael

Whandall, thanks for your tip. I'll remember that one.

--Michael

A different working solution (with minimal changes to the original)

#define SEED_PIN A0
const byte QUANT_CHOICE = 7;
byte choice;

void setup() {
  Serial.begin(57600);
  randomSeed(((long)analogRead(SEED_PIN))<<16);
  choice = random(QUANT_CHOICE);
}

void loop() {
  Serial.println(choice);
  delay(500);
}

Came up with a work-around myself:

#define SEED_PIN A0
const byte QUANT_CHOICE = 7;
byte choice;

void setup() {
  Serial.begin(57600);
  randomSeed(analogRead(SEED_PIN));
  choice = random(1, QUANT_CHOICE);
  choice--;
}

void loop() {
  Serial.println(choice);
  delay(500);
}

I still would like to understand, though. This doesn't appear to be how the function is supposed to work.

--Michael

Oops, meant to write choice = random(1, QUANT_CHOICE + 1);

--Michael

PS. Huh. Looked like it was working for a while, but now returned 0 on more than 20 trials in a row.

I think for the special value 7 (which is used by a %) there should be more noise in the upper part of the long that steps through the sequence.

Some more data to add to what you say.

Works: choice = random(1, 7); choice--; Works: choice = random(6);

Returns 0: choice = random(1, 8); choice--; Returns 0: choice = random(7);

--Michael

That emoticon is supposed to be a numeral 8. --Michael

Whandall,

Your suggestion at #9 always returns 254 for me.

--Michael

edit: Sorry, had a leftover line in my test code. It always returns 0. Your earlier suggestion does appear to return random values.

Returns 0:  choice = random(1, 8); choice--;
Returns 0:  choice = random(7);

both variants end in the same % 7 operation.

long random(long howbig)
{
  if (howbig == 0) {
    return 0;
  }
  return random() % howbig;
}

long random(long howsmall, long howbig)
{
  if (howsmall >= howbig) {
    return howsmall;
  }
  long diff = howbig - howsmall;
  return random(diff) + howsmall;
}
#define SEED_PIN A0
const byte QUANT_CHOICE = 7;
byte choice;

void setup() {
  Serial.begin(57600);
}
void loop() {
  long anaVal = analogRead(SEED_PIN);
  randomSeed(anaVal<<16);
  long lRandom = random();
  Serial.print(F("A0 0x"));
  Serial.print(anaVal, HEX);
  Serial.print(F(" seeded<<16 Random 0x"));
  Serial.print(lRandom, HEX);
  Serial.print(F(" -> "));
  choice = lRandom % (long) QUANT_CHOICE;
  Serial.println(choice);
  delay(500);
}
A0 0x158 seeded<<16 Random 0x386800B0 -> 6
A0 0x141 seeded<<16 Random 0x526700A4 -> 4
A0 0x12F seeded<<16 Random 0x34A9009B -> 6
A0 0x120 seeded<<16 Random 0x5BE00093 -> 0
A0 0x115 seeded<<16 Random 0x9B3008E -> 5
A0 0x10A seeded<<16 Random 0x37860088 -> 4
A0 0x102 seeded<<16 Random 0x2A4E0084 -> 1
A0 0xFB seeded<<16 Random 0x5EBD0080 -> 5
A0 0xF6 seeded<<16 Random 0x167A007E -> 0
A0 0xF0 seeded<<16 Random 0xC90007B -> 3
A0 0xEC seeded<<16 Random 0x5F40079 -> 5
A0 0xEA seeded<<16 Random 0x2A60078 -> 6
A0 0xE7 seeded<<16 Random 0x3DB10076 -> 1
A0 0xE5 seeded<<16 Random 0x3A630075 -> 2
A0 0xE3 seeded<<16 Random 0x37150074 -> 3
A0 0xE1 seeded<<16 Random 0x33C70073 -> 4
A0 0xE2 seeded<<16 Random 0x756E0073 -> 4
A0 0xE0 seeded<<16 Random 0x72200072 -> 5
A0 0xDF seeded<<16 Random 0x30790072 -> 5
A0 0xE1 seeded<<16 Random 0x33C70073 -> 4
A0 0xE0 seeded<<16 Random 0x72200072 -> 5
A0 0xE0 seeded<<16 Random 0x72200072 -> 5

I only partially understand. I'm going to have to put some work into digesting this. Let me ask an elementary question:

After calling randomSeed, you call random() without any arguments ("long lRandom = random();). How does that work? Does it assume that its max value is the maximum value of a long?

Thanks for your help understanding this.

--Michael

edit: there's the damn emoticon again. " long lRandom = random() ; "

Look at the second part of #16, there is the code of the random functions with parameters.

I did not locate the source code of srandom(long) and random() yet.

There are three problems at play…

  1. In general, using analogRead to initialize the random number generator is a bad idea…
    http://forum.arduino.cc/index.php?topic=66206.msg630884#msg630884

    This is a better choice…
    http://forum.arduino.cc/index.php?topic=66206.msg537783#msg537783

    In your case using analogRead is disastrous because of #3 below.

  2. Using modulus to reduce a Lehmer random number generator is a bad idea. But, the alternatives are annoying so a modulus is usually what is used. If you keep the most-significant-bits as the most-significant-bits instead of using modulus your problem will very likely disappear. However, if you insist on continuing to use analogRead a good hash function will work far better for what you are doing than a random number generator.

  3. Low seed values with some prime number divisors are poison with the Park-Miller generator. I’m too lazy to find the thread but there is a detailed discussion on this forum. Given your experience seven is very likely one of those prime number divisors.

Thanks. I've bookmarked those threads and will read through them when I get a chance. This isn't a mission-critical issue for me, just something I stumbled across while I was trying out various things in some test code.

Add one more item to the long (long) list of things to learn about. ;)

--Michael

Whandall: I did not locate the source code of srandom(long) and random() yet.

https://github.com/vancegroup-mirrors/avr-libc/blob/master/avr-libc/libc/stdlib/random.c

@mjward, you are welcome.

(reseedRandom updated with the new value. The remainder of this post is now trivia.)

Bear in mind you will need to use a much larger prime (the constant named HappyPrime in reseedRandom) It does not have to be a Happy Prime; just a prime number. Ideally you should use something slightly more than the "dead zone". I vaguely recall it being about 1.5 million. It's easy enough to write a little sketch to determine where it ends. The dead zone ends at 127,774...

void setup() 
{
  uint32_t seed;
  uint8_t choice;
  
  Serial.begin( 250000 );

  seed = 0;
  do
  {
    ++seed;
    randomSeed( seed );
    choice = random( 7 );

    if ( (seed & 0x0000FFFF) == 0 )
    {
      Serial.write( '.' );
    }
  }
  while ( choice == 0 );

  Serial.println();
  Serial.print( seed );
  Serial.print( F( " --> ") );
  Serial.print( choice );
  Serial.println();
}

void loop() 
{
}

If we stick with Happy Primes the nearest value greater than 127,774 is #1859 = 127807.