Random 0 and 1 integers

Hello,
I need to create an array of integers 0 and 1 with equal distribution. That is, in an aray of 10 numbers, 5 of them should be 0's and 5 others should be 1's. The 0's and 1's must appear in a random manner. Is there a simple way to solve this problem?
Thank you.

Declare your array of 10 integers with 5 of them being set to 0 and 5 being set to 1. The initial order does not matter

Then, as many times as you like, thousands if you choose, select 2 of the array elements using the random() function and swap their values

Note than on most Arduinos the random() function will output the same number sequence each time unless you use the randomSeed() function first

1 Like

Thanks! I wrote some code; it looks rather primitive but works . Here's the code:

int myArray[10] = {0,0,0,0,0,1,1,1,1,1};
int i = 0;
long randNumber1;
long randNumber2;
int temp;

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop() {
  while (i < 100) {                                 //100 iterations
    randNumber1 = random(0,10);
    randNumber2 = random(0,10);
    temp = myArray[randNumber1];                    //temporary integer for 
    myArray[randNumber1] = myArray[randNumber2];    //swapping the values
    myArray[randNumber2] = temp;                    //swapping the values
    i++;
    if (i == 100) {
      printresults();
    }
  }
}


void printresults() {
Serial.println(myArray[0]);
Serial.println(myArray[1]);
Serial.println(myArray[2]);
Serial.println(myArray[3]);
Serial.println(myArray[4]);
Serial.println(myArray[5]);
Serial.println(myArray[6]);
Serial.println(myArray[7]);
Serial.println(myArray[8]);
Serial.println(myArray[9]);
}

The important thing is that it works, but some comments for you

Why is the array declared as int when byte would be plenty big enough ?
Why is i declared as int when byte would be plenty big enough ?
Why are the random number variables declared as long when the largest value that they will hold is 9 ?
Why is temp declared as an int

I note that you never set the value of i back to zero

Why not use a for loop to print the array ?

Thank you for your comments. Indeed, I declared some of the variables wrong. Regrading the value of i, I want the loop to perform the set of 100 iterations only once and then print the results. Here's the updated code:

byte myArray[10] = {0,0,0,0,0,1,1,1,1,1};
byte i = 0;
int randNumber1;
int randNumber2;
byte temp;
byte j;

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop() {
  while (i < 100) {                                 //100 iterations
    randNumber1 = random(0,10);
    randNumber2 = random(0,10);
    temp = myArray[randNumber1];                    //temporary integer for 
    myArray[randNumber1] = myArray[randNumber2];    //swapping the values
    myArray[randNumber2] = temp;                    //swapping the values
    i++;
    if (i == 100) {
      printresults();
    }
  }
}


void printresults() {
  for (j = 0; j < 10; j++) {
    Serial.println(myArray[j]);
  }
}

Then you might as well put the code in setup()

Great idea, I will probably put the code into the setup().
Another question related to this code. Currently the size of myArray is 10, but I am going to incorporate this code into the larger sketch in which I will use serial communication in order to define the size of myArray. Is it possible to change the size of myArray?

Short answer: yes, or achieve the same effect.

Answer: for the moment, just declare your array to be larger than you would ever ask it to be. Changing the array dimension at run time is a bit tricky. You have the memory and there is no savings if you make short arrays and leave a bunch unused.

Later if you indeed have competition among various needs for the scarce resource which is memory, you can worry about dynamic allocation.

But now I ask: is the larger problem going to be the same? N/2 1s and N/2 0s randomly placed in the array of N?

Which makes me ask what are you trying to accomplish? There may be better ways - we can't see where this is headed but already I am just curious.

a7

look at Fisher Yates shuffle. You don't need to randomize 100 times your array

Yes, I already figured out that declaring the big array size could be easier than changing the array size at a run time.

Currently I enter the size of the array into the Serial. The sketch uses this number to fill up the array with 0's and 1's. Then, the swapping is done. It seems like it works - the 0's and 1's are placed randomly, and their number in an array is equal.

This code is an update to the larger sketch that I wrote several months ago. It is used for some kind of experimental setup in which two stepper motors need to be activated in a random pattern. Initially, I used a simple random() command, but now the user asked for some modifications. He still wants the motors to be activated randomly (or pseudo-randomly) but the number of the left and the right activations in the entire sequence must be equal. That is, if the sequence consists of 10 activations total, there must be 5 times in which the left motor is activated, and 5 times in which the right motor is activated.

Thanks!

here is an example

byte myArray[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
const byte arraySize = sizeof myArray / sizeof myArray[0];

// Fisher–Yates shuffle
void shuffle() {
  for (byte i = arraySize - 1; i > 0; --i) {
    byte r = random(0, i + 1);
    byte tmpSwap = myArray[i];
    myArray[i] = myArray[r];
    myArray[r] = tmpSwap;
  }
}

void show() {
  for (auto &n : myArray) Serial.print(n);
  Serial.println();
}

void setup() {
  Serial.begin(115200); Serial.println();
  randomSeed(analogRead(A0));    // randomize
}

void loop() {
  shuffle();
  show();
  delay(1000);
}
1 Like

Arduino.h:

typedef uint8_t byte;

Better use a signed type for that loop.

well it is indeed usually best when you go downwards to use a signed type (because >= 0 is always true) but here I stop at 1 so it works

1 Like

if you want no array but just a function that gives you 0 or 1, then this could be an approach

byte draw(byte totalCount, bool reset = false) {
  static byte zeroCount = 0;
  static byte drawCnt = 0;
  byte r;
  if (reset) zeroCount = drawCnt = 0;

  if (zeroCount >= (totalCount / 2)) r = 1;
  else if ((drawCnt - zeroCount) >= (totalCount / 2)) r = 0;
  else r = random(0, 2); // 0 or 1
  drawCnt++;
  if (r == 0) zeroCount++;
  return r;
}

void get(byte cnt) {
  Serial.print(draw(cnt, true));
  for (byte i = 1; i < cnt; i++) Serial.print(draw(cnt));
  Serial.println();
}

void setup() {
  Serial.begin(115200); Serial.println();
  randomSeed(analogRead(A0));    // randomize
}

void loop() {
  get(10); // ask for 10 bits with equal repartition 
  delay(2000);
}

Yup

If all you want is a long sequence of 1s and 0s with 0.5/0.5 probable I do not see a need to create it ahead of time.

Every time a bit is needed, feed out a random 1 or 0.

Count the 1s, count the 0s. Maybe even use the current counts to inform the random bit creation.

If 1s are running hot, make it the bit less likely.*

Unless your need is to have precisely 100 0s and precisely 100 1s, or whatever N is.

Even then it seems like it could be faked…

a7

That is a nice shuffle. Let's test that.

I start with 60000 bytes, and the first half is 0, the second half is 1.
After shuffling I count the zeros in the first half to check the percentage.

Before shuffling : 100.00%
Shuffle 1 time : 50.07%
Shuffle 2 times : 49.98%
Shuffle 3 times : 49.76%
Shuffle 4 times : 50.07%

That is very good !

// DoTheShuffle.ino
//
// By : Koepel, 14 December 2021
// Fisher-Yates shuffle
// From example by Arduino user J-M-L
//   https://forum.arduino.cc/t/random-0-and-1-integers/935832/12
// Adapted for Raspberry Pi Pico in Wokwi simulation
// Raspberry Pi Pico has 264kbyte internal ram.
//

#define SIZE 60000UL        // use an even number
byte myArray[SIZE];
const size_t arraySize = sizeof myArray / sizeof myArray[0];


// Fisher–Yates shuffle
void shuffle() 
{
  for (size_t i = arraySize - 1; i > 0; --i) 
  {
    size_t r = random(0, i + 1);
    byte tmpSwap = myArray[i];
    myArray[i] = myArray[r];
    myArray[r] = tmpSwap;
  }
}


void show() 
{
  for (auto &n : myArray) 
    Serial1.print(n);
  Serial1.println();
}


void tell()
{
  // Count zeros in first half
  size_t count = 0;
  for( size_t i=0; i<SIZE/2; i++)
    if( myArray[i] == 0)
      count++;

  Serial1.print( "Percentage zeros in first half is: ");
  float percentage = float(count) / float(SIZE/2) * 100.0;
  Serial1.println( percentage);
}


void setup() 
{
  Serial1.begin(115200);
  Serial1.println("The sketch has started");

  randomSeed(analogRead(A0));    // randomize

  // First half with zeros
  for( size_t i=0; i<SIZE/2; i++)
    myArray[i] = 0;
  // Second half with ones
  for( size_t i=SIZE/2; i<SIZE; i++)
    myArray[i] = 1;

  // show();
  Serial1.println( "First one is before shuffling");
  tell();
}


void loop() 
{
  shuffle();
  // show();
  tell();
  delay( 1000);
}

The sketch in Wokwi simulation:

[ADDED] When using the method of just exchaging 100 random numbers, then it is obvious that it has almost no effect in a array of 60000. I have enlarged the sketch to test it. To reach 50%, I estimate that about between 100000 and 200000 exchanges of two random values are needed.

1 Like

This would tend to show that the built in random generator is petty unbiased (otherwise Fisher–Yates does not work so well)

In the wokwi @Koepel offers the opportunity to try the other scrambler. After some time it got to

Number of shuffles = 96700, Percentage zeros in first half is: 51.97

but progress was really stalling. Asymptotic approach to 50/50.

As the array gets randomized, flipping two elements at random becomes increasingly unlikely to forward the progress. <- NO, that's not what's happening

I lost patience, decided to stop when it went to 52 percent.

Yes, I reduced the delay.

a7

1 Like