Random Function omitting certain numbers

When using the Random Function, is there any way to omit certain numbers? Also, as I am only using 65 numbers, can I store the result in a Byte?

In this example code, how would I achieve this:

long randNumber; // Can I use byte randNumber?

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

void loop() {
  // print a random number from 0 to 64
  randNumber = random(65); // If randNumber is say 8, 12, or 16 try again?
  Serial.println(randNumber);

  delay(50);
}

Thanks

Rob

Hi Rob

Yes and yes

For example

do randNumber = random(65); while (randNumber == 8 or randNumber == 12 or randNumber == 16);

Welcome to the forum

Welcome to the forum

Methods like this and that suggested by @PaulRB

byte randNumber;  // Can I use byte randNumber?

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

void loop()
{
    // print a random number from 0 to 64
    randNumber = random(65);  // If randNumber is say 8, 12, or 16 try again?
    if (randNumber == 8 || randNumber == 12 || randNumber == 16)
    {
        Serial.print("skipped ");
        Serial.println(randNumber);
        delay(1000);
    }
    else  //use the random number
    {
        Serial.println(randNumber);
        delay(50);
    }
}

are OK to skip a small number of cases

As a matter of interest, what is the application that it will be used for and were your examples real values that you want to use ?

Thank you Paul, I’ll give that a go.

Cheers,

Rob

Thank you Bob, I’ll give this a go as well.

As a matter of interest: I’m developing a Braille Game for my blind grandson, which involves the rest of the family (all too often he is left to occupy himself). It’s basically a box with seven buttons and six LEDs, where after pressing the “start” button, a contestant is given audio feedback with the name of a random braille cell (hence the code above) to enter their guess using a combination of six buttons. If they guess right then a positive audio feedback is given, else a negative audio feedback is given.

I am hoping to use a shift register to send the chosen combination output to an array of 6 LEDs, thereby displaying the braille cell; so need to send the binary value of the chosen braille cell to the register. I can do this, but have struggled with some of the braille cells, because some of the 64 cells are used as prefixes in conjunction with other braille cells, and I only want to include single cells such as “a to z” and some contractions and Punctuation cells.

Hope this makes sense?

Rob

An alternative approach uses an array with all valid values, and generates a random index for the array. It will guarantee always a valid value in the first try.

The price is the array takes memory, in your case 62 bytes.

simplified example, random prime below 100, there would be 75 values to skip (75% chance).

int number;

const int NRVAL = 25;
uint8_t validValues[NRVAL] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };

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


void loop()
{
  number = validValues[random(NRVAL)];
  Serial.println(number);
  delay(1000);
}

I can't count more than seven items.

uint8_t validValues[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
const int NRVAL = sizeof validValues / sizeof *validValues;

a7

Thank you Rob, I’ll certainly give this a try. I like the idea of having a guaranteed output for the 8 bit variable.

All ideas presented so far have given me good food for thought, and greatly appreciated.

Not sure what you are meaning here A7, can you explain please?

Rob

alto777 let the computer determine the size of the array, where my example above was hard coded, which is less flexible. So a retry including the hint from alto777 (thanks)

int number;

uint8_t validValues[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
const int NRVAL = sizeof validValues / sizeof *validValues;

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

void loop()
{
  number = validValues[random(NRVAL)];
  Serial.println(number);
  delay(1000);
}

In this version you can add as many primes as you want in the array and the NRVAL is determined compile time. So less chance on typos .

Ah, yes, I get it now, thanks for the explanation!

When both declaring the number of elements in the array and supplying initial values, the compiler will complain if you specify too many -- they don't fit. But not a peep if you specify too few, which has legitimate uses, e.g.

// going to calculate the rest, but need to seed the first two
unsigned fibonacci[100] = {0, 1};

So better not to declare the size at all, and let the computer do what it's really good at: counting and math. Unlike other languages, in C the number of elements in an array is not automatically available after declaration. But you can get the sizeof the whole thing, and divide by the size of the first element.

Thanks Ken I will go and read up on sizeof, it’s new to me. But I understand what you are saying.

The following only requires one call to random without retries, so it has a predictable run time. This approach should work well If the number of forbidden values is small.

template <class T, size_t n> size_t arraySize(T const (&)[n]) { return n; }

long myRand(long const low, long const high) {
  long const forbidden[] {8, 12, 16};
  long r {random(low, high - arraySize(forbidden))};

  for (long const& f: forbidden) {
    if (r >= f) {
      ++r;
    }
  }

  return r;
}

Usage:

Serial.println(myRand(0, 64));

Instead of the arraySize template, you can also use the suggestion given above.

const int NRVAL = sizeof validValues / sizeof *validValues;

It is a matter of personal preference but I would write this as

const int NRVAL = sizeof(validValues) / sizeof(validValues[0]);

In practice it does the same thing but I think that it is more obvious what it is doing

Before anyone comments, I am fully aware that sizeof is a macro so the parentheses are not needed and that a pointer to the array will return the size of the first element of the array

Of course, you could go the other way and extend the macro

#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))

byte arr1[] = { 1, 2, 3, 4 };
unsigned long arr2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

void setup()
{
    Serial.begin(115200);
    byte count1 = ARRAY_LENGTH(arr1);
    Serial.println(count1);
    byte count2 = ARRAY_LENGTH(arr2);
    Serial.println(count2);
}

void loop()
{
}

sizeof is an operator; the parentheses are required when applied to a type, e.g. sizeof(int) -- maybe to make parsing easier?

I am not alone in just always using parentheses. Less cognitive load.

I am with you regarding always using parentheses, for the same reason

I would recommend a DFplayer Mini for the audio feedback.

For the LEDs, do you really need a shift register? Will you not have 6 available Arduino pins?

Don't forget you can use the analog input pins as digital inputs/output pins on most types of Arduino.

This is not a very good way to initialise the random number seed. However you have a much better way built into your game.

Use this time to simply call the random number function until you press the button. This will make the random number generator stop at the current value at the very instant the button is pressed. As this is very rapidly changed there is no way anyone can predict what the next number will be generated in the sequence.

This is simply the very best way of insuring, in effect, a random seed from a deterministic system.

I’m using the DY-SV8F for the audio. And I am using the analogue pins for the LEDs in my prototype. It does actually work ok, but I’m on a learning curve, and seeing shift registers for the input and outputs as simplifying not only the wiring, but the code as well. Simply comparing the bit pattern of the user input with the bit pattern of the correct answer would give me the same bit pattern for the relevant audio track number - I’m hoping! I am also thinking of using touch sensitive pads to replace the tactile buttons, but that’s another learning curve!