4

In general, when I need to generate a random value within a closed interval (considering B as the beginning and E as the end of the interval) in C, I use one of the following approaches:

Approach 1:

n = round(B + ( (float)rand() / RAND_MAX ) * (E - B));

Approach 2:

n = B + rand()%(E - B+1);

Both of them consider the initialization of the random seed with the function time():

srand(time(NULL));

In Linux systems, both approaches seem good enough for generating interesting random values. However, in Windows systems, sometimes the numbers do not appear to be random enough.

Investigating these systems, I've found that the value of RAND_MAX is different. In the Linux systems that I have tested RAND_MAX is 2147483647. In these windows systems with a not-so-good behavior, RAND_MAX is 32767.

I think that with a larger RAND_MAX value we can generate better random numbers. But I'm not sure.

With this in mind, my question is: Is there some good way of generating interesting random numbers (within a closed interval) that work well on all systems?

Besides that, my approaches 1 and 2 are good approaches for generating random numbers within a closed interval?

Zaratruta
  • 2,097
  • 2
  • 20
  • 26
  • 1
    I think both methods are equivalent. But if `RAND_MAX < (E - B)`, you get poor results in both versions. – Barmar Oct 01 '21 at 00:28
  • @Barmar I agree. This assumes that (E - B) <= RAND_MAX – Zaratruta Oct 01 '21 at 00:30
  • 3
    Personally, I use [PCG](https://www.pcg-random.org/) for high quality pseudo random numbers; the C implementation has a routine for uniform numbers in a range – Shawn Oct 01 '21 at 00:56
  • I believe the C89 dictated that the minimum value of RAND_MAX to be 32767 – Mitch Wheat Oct 01 '21 at 00:58
  • 5
    OP: See https://stackoverflow.com/q/10984974/9952196 for why using `%` is a not ideal approach. – Shawn Oct 01 '21 at 01:01
  • 4
    “Best” is a matter of opinion, and there are several issues you have not addressed in your question. First, either `rand() / something` or `rand() % something` is non-uniform—the number of values `rand` generates is usually not a multiple of the number of values in your target set. So some elements of the target set will be generated more often than others. The difference may be slight, but certainly the **best** way to generate random numbers would have zero difference. Will `E-B` ever be more than a small fraction of `RAND_MAX`? The greater it is, the greater the non-uniformity will be. – Eric Postpischil Oct 01 '21 at 01:06
  • 1
    State of the art: Lemire, Daniel. "Fast random integer generation in an interval." *ACM Transactions on Modeling and Computer Simulation (TOMACS)* 29, no. 1 (2019): 1-12 – njuffa Oct 01 '21 at 08:52
  • 1
    The `round` method in the question generates the endpoints with about half the frequency of other points. Values for the division that are in [0, ½)/(E−B) will yield a final result of B, while values in [½, 1½)/(E−B) will yield a final result of B+1. The latter interval is twice the former, and all the interior points have an interval of that length. Then the final interval is [E−B−½, E−B]/(E−B), which is back to about half of the interior intervals. Is that what you want? – Eric Postpischil Oct 01 '21 at 11:47
  • Nice contributions! – Zaratruta Oct 01 '21 at 20:45

0 Answers0