Further on Arduino Random Numbers…

After my previous article on Random numbers I posted on the Arduino forum looking for similar experiences.

One big result of the responses: a second, simpler way to generate the numbers. It’s based on not the change in values, but simply the least significant bit of each value, which fluctuates considerably. According to the Wikipedia article on hardware random number generators, it qualifies as random, but is still in need of debiasing (turns out that ‘unbias’ is not the proper term!)

The result? A simple, somewhat random, but biased option is the following code:

unsigned long seedOut(unsigned int noOfBits)
{
  // return value with 'noOfBits' random bits set
  unsigned long seed=0;
  while (noOfBits--)
    seed = (seed<<1) | (analogRead(0)&1);
  return seed;  
}

You no longer need bitOut() from the previous code, and that removes the two static longs used in that function, for eight bytes of valuable memory saved.

This function leads to a pretty good spread of values, and seems random enough, even without the biasing. I’d recommend it as the seed for the randomSeed() generator, but it’s fast enough to use directly if you prefer. However, in that case, I think you should still debias it with the following code:

unsigned long seedOut(unsigned int noOfBits)
{
  // return value with 'noOfBits' random bits set
  unsigned long seed=0, limit=99;
  int bit0=0, bit1=0;
  while (noOfBits--)
  {
    for (int i=0;i<limit;++i)
    {
      bit0=analogRead(0)&1;
      bit1=analogRead(0)&1;
      if (bit1!=bit0)
        break;
    }
    seed = (seed<<1) | bit1;
  }
  return seed;  

The ’99’ in the code is the bias limit – adjust as you want, in line with what I mentioned in the previous article.

Finally, if you just need a ‘good enough’ random generator for most projects, here’s one you can use to seed the internal random generator easily, in just a few lines of code in the setup() function:

unsigned long seed=0, count=32;
while (--count)
  seed = (seed<<1) | (analogRead(0)&1);
randomSeed(seed);

For most projects (ie just about everything aside from commercial grade encryption I suspect), this code should do the job.

6 thoughts on “Further on Arduino Random Numbers…

  1. Von Neuman filtering requires that two bits do not have any correlation between them. If you make two successive reads from the analog input, the propability for them being the same is high. The output of this implementation propably has more numbers with alternative bit sequences, such as 0xAA and 0x55.

    My proposed improvements are to use two separate analog inputs and compression.

    Let’s imagine that you have two sources where the other one is constant and the other one changes with random intervals. You would read always either 01 or 00. And your random bit output would be constant 0. But if you take into account how many times you read before input changes, then your output includes the randomness in timing. That’s compression.

  2. Actually, Von Neumann filtering is specifically for number lists that are not truly random – after all, there is no need to remove bias if the stream is completely random. As for repeated calls returning the same value, removing that is the purpose of the extra code in function #2 here. Unfortunately, with the Arduino there is always the possibility of grabbing a non-changing bit (for example, accidentally using an analog port that is in use) – however, these functions do improve the randomness of the initial value.

  3. Two comments. With your debiasing code, if the result of analogRead were to wander slowly, then your code would be guaranteed to produce either 01010101 or 1010101, which would likely be worse than your simple case.

    And on to the simple case, why throw away the potential extra random bits of analogRead? Why not instead:

      seed = (seed<<1) ^ analogRead(0);

  4. There’s any number of patterns that can ‘jam’ the unbiasing formula – for instance, 010101->000 and 101010->111 – that’s because the unbiasing is meant for *random* data. Arduinos are not random – just display the output from analogRead(0) and you’ll see a small group of values repeating. If you used these values directly (or used them to add to a seed as you showed code for) you’d be nowhere near random in your outputs. Far better to use a bit of code to read the port for an initial random seed, and then use the random number generator in C from then on. And to get a wider range of randomish numbers, use only the lower bit from each read. The goal is not a precision random number generator, but something that is reasonably random from a human’s point of view for whenever the program starts up.

  5. I know you posted this a number of years ago, but I came across it yesterday and proved very helpful for me – just what I needed for a very simple project that needed some randomness that the suggested solution in the arduino documentation just wasn’t producing. So many thanks for posting!

  6. Your code only works if the A0 pin is left floating.
    Here is a version using all the analog channels

    unsigned long seed=0;
    byte count=32;
    while (–count) seed = (seed<<1) | ((analogRead(0)+ analogRead(1)* analogRead(2)+ analogRead(3)+ analogRead(4)+ analogRead(5)+ analogRead(6)+ analogRead(7)))&1);
    randomSeed(seed);