2

What i would love to do is to create a function that takes a parameter that is the limit of which number the random generation should create. I have experienced that some generators that just repeat the number generated over and over again.

How can I make a generator that doesn't return the same number consecutively. Can someone please help me to achieve my goal?

int randomGen(int max)
{
  int n;      
  return n;
}
p.campbell
  • 98,673
  • 67
  • 256
  • 322
user265767
  • 559
  • 3
  • 12
  • 27

4 Answers4

7

The simplest way to get uniformly distributed results from rand is something like this:

int limited_rand(int limit)
{
  int r, d = RAND_MAX / limit;
  limit *= d;
  do { r = rand(); } while (r >= limit);
  return r / d;
}

The result will be in the range 0 to limit-1, and each will occur with equal probability as long as the values 0 through RAND_MAX all had equal probability with the original rand function.

Other methods such as modular arithmetic or dividing without the loop I used introduce bias. Methods that go through floating point intermediates do not avoid this problem. Getting good random floating point numbers from rand is at least as difficult. Using my function for integers (or an improvement of it) is a good place to start if you want random floats.

Edit: Here's an explanation of what I mean by bias. Suppose RAND_MAX is 7 and limit is 5. Suppose (if this is a good rand function) that the outputs 0, 1, 2, ..., 7 are all equally likely. Taking rand()%5 would map 0, 1, 2, 3, and 4 to themselves, but map 5, 6, and 7 to 0, 1, and 2. This means the values 0, 1, and 2 are twice as likely to pop up as the values 3 and 4. A similar phenomenon happens if you try to rescale and divide, for instance using rand()*(double)limit/(RAND_MAX+1) Here, 0 and 1 map to 0, 2 and 3 map to 1, 4 maps to 2, 5 and 6 map to 3, and 7 maps to 4.

These effects are somewhat mitigated by the magnitude of RAND_MAX, but they can come back if limit is large. By the way, as others have said, with linear congruence PRNGs (the typical implementation of rand), the low bits tend to behave very badly, so using modular arithmetic when limit is a power of 2 may avoid the bias problem I described (since limit usually divides RAND_MAX+1 evenly in this case), but you run into a different problem in its place.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Of course, if `limit > RAND_MAX`, this will result in division by 0. (But maybe that's a good thing to catch cases where you're not truly getting uniform random numbers from the range you want.) – jamesdlin Apr 29 '12 at 00:45
  • Yes.. if you're worried that might really happen, you should wrap `rand` with a function that calls `rand` multiple times and appends the bits until you have a uniform distribution on a large known fixed power-of-two range. – R.. GitHub STOP HELPING ICE Apr 29 '12 at 01:27
2

How about this:

 int randomGen(int limit)
 {
    return rand() % limit;

 }
   /* ... */
 int main()
 {
    srand(time(NULL));
    printf("%d", randomGen(2041));

    return 0;
  }
Nemanja Boric
  • 21,627
  • 6
  • 67
  • 91
0

Without explicit knowledge of the random generator of your platform, do not do rand() % max. The low-order bytes of simple random number generators are usually not random at all.

Use instead (returns a number between min inclusive and max non-inclusive):

int randomIntegerInRange(int min, int max)
{
    double tmp = (double)rand() / (RAND_MAX - 1.);
    return min + (int)floor(tmp * (max - min));
}

Update: The solution above is biased (see comments for explanation), and will likely not produce uniform results. I do not delete it since it is a non natural example of what not to do. Please use rejection methods as recommended elsewhere in this thread.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • @Matt: this works. With other knowledge from rand(), I'd do modulus with a power of 2 and rejection. But here, if rand() is a linear congruential crap, there is no better way. – Alexandre C. Sep 19 '10 at 18:25
  • This solution does not fix the bias. – R.. GitHub STOP HELPING ICE Sep 19 '10 at 18:36
  • @R. It is very hard to come with a rand() implementation which has bias in its higher order terms. There are problems with modulus, but not with this approach. What bias are you talking about ? – Alexandre C. Sep 19 '10 at 18:41
  • If `max-min` does not go evenly into `RAND_MAX+1`, some outputs will have more inputs mapping onto them than others. – R.. GitHub STOP HELPING ICE Sep 19 '10 at 20:56
  • @R. In this case, this works fine. I draw a uniform double between 0 and max - min (exclusive). There is no bias at all if rand() yields a uniform integer between 0 and RAND_MAX. This is the whole point of using doubles. – Alexandre C. Sep 19 '10 at 21:10
  • 1
    R is correct, there *is* a bias. It's a simple pigeonhole principle problem - if you try to map every possible `rand()` value onto an output integer, and the number of possible outputs doesn't exactly divide the number of possible `rand()` values, then some output values will be mapped from less `rand()` values than others. Hence, bias. – caf Sep 20 '10 at 03:29
  • @Alexandre: you do not draw a uniform double between 0 and `max-min` using that algorithm. The probability distribution for resulting doubles has weight **zero** on the vast majority of possible doubles in that range, with nonzero spikes here and there. Each of the spikes has equal probability `1/(RAND_MAX+1)`, but when you rescale to map to an integer, different numbers of these spikes get mapped onto different integers, giving bias. – R.. GitHub STOP HELPING ICE Sep 21 '10 at 01:32
  • @R., @caf. Understood. I never thought about that issue (the bias is little, but probably statistically significant). Usually, I use rejection on the low order bits of a *known* rng. – Alexandre C. Sep 21 '10 at 08:23
0

Any pseudo-random generator will repeat the values over and over again with some period. C only has rand(), if you use that you should definitively initialize the random seed with srand(). But probably your platform has better than that.

On POSIX systems there is a whole family of functions that you should find under the man drand48 page. They have a well defined period and quality. You probably find what you need, there.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177