Nae
Nae

Reputation: 15335

What's the best way of generating a random number in a discontinuous range?

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?

Upvotes: 3

Views: 374

Answers (2)

chqrlie
chqrlie

Reputation: 144715

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)];

Upvotes: 5

Aziz
Aziz

Reputation: 20705

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.

Upvotes: 10

Related Questions