3

Is there a better way than:

#define BOUND 7

int r;
int e = 1;

r = rand() % BOUND;

while (r == e){

    r = rand() % BOUND;
}

for generating numbers in a range except for a value e?

Nae
  • 14,209
  • 7
  • 52
  • 79

2 Answers2

10

What you're asking for is generating a random number in the range [0, BOUND) excluding the value e

The algorithm explained here seems to be the best way to do it without using a loop.

Here is the C code:

#define BOUND 7

int r;
int e = 1;

r = rand() % (BOUND-1);

if (r >= e){
    r = r+1;
}

So, you basically generate a value in the range [0, BOUND-1), and if the value is greater than or equal to the excluded value e, you increment the random number by one.

Keep in mind that using rand with % does not guarantee a strict uniform distribution across the generated numbers. For more info, check out this question/answers.

Aziz
  • 20,065
  • 8
  • 63
  • 69
5

To generate a pseudo-random number in a range with a uniform distribution among values, it is much more reliable to use the magnitude of the value returned by rand() rather than its remainder for the division rand() % BOUND:

int r = (long long)rand() * BOUND / (RAND_MAX + 1LL);

rand() returns a value between 0 and RAND_MAX included: the division must use RAND_MAX + 1LL so the result is in range 0 included .. BOUND excluded (as commented by chux).

If you want to exclude a given value, reduce the range by one and adjust the result:

#define BOUND 7

int r = (long long)rand() * (BOUND - 1) / (RAND_MAX + 1LL);
if (r >= 1) { // shift values 1..5 to 2..6
    r += 1;
}

Here is a more general version:

// select a random value from a set
int set[] = { 0, 2, 3, 4, 5, 6 };
int r = set[(long long)rand() * (sizeof(set) / sizeof(*set)) / (RAND_MAX + 1LL)];
chqrlie
  • 131,814
  • 10
  • 121
  • 189