1

I am looking for a way of generating booleans rapidly. For booleans, one usually uses random(0,2); but in my case I need about 250 booleans and calling random every time is slow.

So I thought about using all bits of a random number on the whole range as such:

randomSeed(100); // A seed to always keep the same sequence
long rdm = random(MIN,MAX);  // Generate a number in range MIN,MAX of type long
long mask = 1;
for(int i=0; i<32; i++){
    if((rdm>>i)&mask){
        //do something
    } else {
        //do something else
    }
}

But with this I have three questions:

  1. What are MIN and MAX so that the LONG random uses all bits, with value ranging from -2,147,483,648 to 2,147,483,647 (arduino long type). I tried several MIN and MAX, also simply random(); but without success.
  2. Is it a valid approach? Do I expect each bit to be uniformly distributed? Should I use fewer bits, e.g. random(0, 2^16); for a "better" distribution?
  3. Is there some seed known to be good or bad at this?

My project

I am working on a device made of Neopixel LED strips. It is for a visual neuroscience experiment where each "pixel" is either ON or OFF. I need the speed to be able to reach high refresh rate (60-100Hz), with normal statistical distribution to avoid bias in neuron response analysis. With this approach, I can reach the desired speed but I'm concerned about the statistics. So I need a better understanding of random()'s behaviour to do it right!

5
  • are you sure it will be faster?
    – Juraj
    Commented Jun 22, 2020 at 11:20
  • 1
    Good pseudorandom number generators are few and far between. I would not trust one from a microcontroller's library, which is optimized for speed rather than optimal statistic properties. On AVR, I would prefer the underlying no-parameter random(), which has 31 usable bits, over the one from the Arduino core, which only adds bugs. And I strongly recommend you test for the statistical properties you care about before committing to any PRNG. Commented Jun 22, 2020 at 12:16
  • @Juraj yes it's faster. Including the communication with Neopixel, when I was drawing one boolean per LED, I was displaying at around 30-40Hz. With this method I need only 8 random numbers to get the 250 bits, that allow me to display at 100Hz. Quick benchmark (Arduino Uno) to assign value to each LED (237 total): This method: 1.6ms -- One rand per LED: 22ms -- (Neopixel communication: 2.05ms)
    – Tom-tbt
    Commented Jun 22, 2020 at 14:47
  • @EdgarBonet Thanks for the advice, I'll use just random() then to have the 31 bits. I'm using fixed seeds so I'm also checking how they distribute.
    – Tom-tbt
    Commented Jun 22, 2020 at 14:51
  • @Juraj I think this blog post is a relevant benchmark
    – Tom-tbt
    Commented Jun 22, 2020 at 15:32

2 Answers 2

1
  1. I didn't try myself, but in the documentation it shows the MAX value is 2,147,483,647, which is 2^31-1. The MIN value I expect is -2^31, thus -2,148.483.648. Wondering what you mean by 'without success'.
  2. Yes this is a valid approach. A 'perfect' random generator should be able to generate all values with an equal distribution. Since the values are within [-2^31, 2^31-1] this means all values within a 32 bit value is used, which automatically means all bits are also evenly distributed. So you can pick individual bits (as long as you use the entire MIN/MAX range).
  3. In principle all seeds are good, as long as they are random. In the documentation it is advised to take an unconnected analog pin value. If you don't have one unconnected, you can use e.g. the millis function.
6
  • 1
    Arduino's two-parameter random() won't work as expected if max-min is larger than LONG_MAX. Commented Jun 22, 2020 at 12:21
  • @EdgarBonet Seems to me like a bug in the original Arduino (library). Using t hat library you refer to, or using 31 bits instead of 32 is than a solution. 8 instead of 7 calls needed, to get 250 booleans. Commented Jun 22, 2020 at 13:07
  • 1
    I wanted to show the weird output I got for MIN-MAX [-2^31, 2^31-1], but the source code say enough already. Thanks @Edgar
    – Tom-tbt
    Commented Jun 22, 2020 at 14:55
  • @Michel On the second point, I was more wondering specifically about the implementation in Arduino. Is it good enough to assume that all 31 bits are uniformly distributed? If not, taking for example only the first 24 bits should give better results, right? The previously assumed uniformity for these 24 bits is now an average of 2^7 values.
    – Tom-tbt
    Commented Jun 22, 2020 at 15:04
  • If the values returned are evenly distributed, it would not matter if you check bits one by one or the total value. Assume you use [0... max] and get a uniformly distributed 31-bit values, using 24 bits or 31 bits will not make the accuracy or results better. Commented Jun 22, 2020 at 15:08
0

The random() function returns a number between 0 and RANDOM_MAX (0x7FFFFFFF). The random(min, max) function takes the value from random() and manipulates it to fit into the specified range (calculate the offset difference, modulus the random value by that difference, then add the lower offset).

That means that the widest range you can get is from random() directly, whilch is the same as random(0, RANDOM_MAX). However that is only ever going to be 31 bits, so your most significant bit will always be zero.

That's not what you want.

The best you can do to get 32 bits of random data is to take two random 31 bit values and combine them. Maybe left shifting one value by one bit and the XORing them together would be enough:

uint32_t rand1 = random();
uint32_t rand2 = random();
uint32_t fullrand = (rand1 << 1) ^ rand2;

Alternatively just working with 31 bits instead of 32 may be enough for your needs and would be faster than generating two numbers and combining them just to fill that one extra bit.

3
  • Thanks also for your answer, it adds to the comments of @Edgar. I was trying to understand why I was limited to 31 bits and now it's clear. 31 bits will do perfectly fine.
    – Tom-tbt
    Commented Jun 22, 2020 at 15:11
  • random(0, RANDOM_MAX) returns a random number between 0 and RANDOM_MAX-1 (inclusive), with 0 twice as likely as the other outputs. Commented Jun 22, 2020 at 16:02
  • Naaaasty. A good enough reason not to use Arduino's horrible overloaded versions of a standard library function.
    – Majenko
    Commented Jun 22, 2020 at 16:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.