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?

11
  • 1
    do you need values to be equally distributed? Commented Nov 13, 2017 at 18:39
  • BTW, I don't understand what your code is supposed to do Commented Nov 13, 2017 at 18:40
  • 3
    Make an array of possible values and then randomly pick from it. Commented Nov 13, 2017 at 18:41
  • 3
    generate in range BOUND-1 and add 1 if it is >= e Commented Nov 13, 2017 at 18:43
  • 1
    Partial dupe : Generating a uniform distribution of INTEGERS in C. Commented Nov 13, 2017 at 18:45

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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

3 Comments

int r = (long long)rand() * BOUND / RAND_MAX; causes an unneeded distribution bias and can leave r with the value of BOUND. This could be fixed with int r = (long long)rand() * BOUND / (RAND_MAX + 1LL);.
@chux: absolutely! I should have been more careful.
Right, I seem to have messed that up. Sorry. @chqrlie

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.