This question already has answers here:
srand() — why call it only once?
(7 answers)
Closed 4 years ago.
I'm trying to generate 10,000 random numbers in a row in C and am having trouble getting random or even randomish results using the pseudo RNG. I used modulus in a way that I think should create uniformity, which it does, but the results are equivalent to 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3 etc. when run in a loop in another function calling RNG(4).
int RNG(int n) {
int range = RAND_MAX - (RAND_MAX % n);
srand(time(NULL));
int x = rand();
while (x > range) {
x = rand();
}
return x % n;
}
Any way to get it closer to 1,3,2,0,2,3,1,0,0,3,2,0,1 etc. would be appreciated!
Thank you!
EDIT: Thanks for the responses everyone! Moved the seeding to the start of the function calling RNG and everything is dandy now!
Do not call srand every time you want to generate a number. srand initializes the pseudo-random number generator and is intended to be called just once at the start of your program, or when you want to reset the generator. By resetting it every time, you are forcing rand to generate the same numbers every time you call it within each second on the clock.
Do not use x % n to reduce the number to a desired range. Old implementations of rand are notoriously bad and have patterns in the low bits. Instead, use x / ((RAND_MAX+1u) / n).
The code int range = RAND_MAX - (RAND_MAX % n); is flawed. Suppose n is 4 and RAND_MAX is 7, meaning rand returns 0 to 7. This code sets range to 4, and then while (x > range) x = rand(); discards 5, 6, and 7, while it retains 4. There are two bugs here: The code keeps the five values 0, 1, 2, 3, and 4, which is a mismatch to (not a multiple of) the desired range of 4, and it unnecessarily discards values. If we had kept 4, 5, 6, and 7, we would have a match. You could use:
unsigned range = (RAND_MAX + 1u) - ((RAND_MAX + 1u) % n);
and:
while (x >= range) x = rand();
If you are using C++, switch to using std::uniform_int_distribution. If you are using C, check the quality of rand in your implementation or switch to another generator such as the POSIX srandom and random.
As noted elsewhere, the fix to the repeated numbers is to move the call to srand(time(NULL)) outside this function and call it only once per program at the beginning.
As for why you're getting repeated numbers: The function is being called several times per second. Each time the function executes in a given second, time(NULL) returns the same number, which this code uses to seed the random number generator.
The sequence of random numbers generated from a particular seed will always be the same. This code takes the first number from that sequence, which is always the same for one second, until time(NULL) returns a new value.
Related
This question already has answers here:
Rand() % 14 only generates the values 6 or 13
(3 answers)
Closed 1 year ago.
I have a problem, I want to use rand() to get a random number between 0 and 6, but it always gives me 4 at each run, even when I call srand(time(NULL))
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
srand(time(NULL));
int rd = rand() % 7;
printf("%d\n", rd);
return (0);
}
output is 4 at each run
There are two fundamental problems with your code which, in combination, produce the curious result you're experiencing.
Almost anyone will warn you about the use of the rand() interface. Indeed, the Mac OS manpage itself starts with a warning:
$ man rand
NAME
rand, srand, sranddev, rand_r -- bad random number generator
Yep, it's a bad random number generator. Bad random number generators can be hard to seed, among other problems.
But speaking of seeding, here's another issue, perhaps less discussed but nonetheless important:
Do not use time(NULL) to seed your random number generator.
The linked answer goes into more detail about this, but the basic issue is simple: the value of time(NULL) changes infrequently (if frequently is measured in nanoseconds), and doesn't change much when it changes. So not only are you relying on the program to not be run very often (or at least less than once per second), you're also depending on the random number generator to produce radically different values from slightly different seeds. Perhaps a good random number generator would do that, but we've already established that rand() is a bad random number generator.
OK, that's all very general. The specific problem is somewhat interesting, at least for academic purposes (academic, since the practicial solution is always "use a better random number generator and seed it with a good random seed"). The precise problem here is that you're using rand() % 7.
That's a problem because what the Mac OS / FreeBSD implementation of rand() does is to multiply the seed by a multiple of 7. Because that product is reduced modulo 232 (which is not a multiple of 7), the value modulo 7 of the first random number produced by slowly incrementing seeds will eventually change, but it will have to wait until the amount of the overflow changes.
Here's a link to the code. The essence is in these three lines:
hi = *ctx / 127773;
lo = *ctx % 127773;
x = 16807 * lo - 2836 * hi;
which, according to a comment, "compute[s] x = (7^5 * x) mod (2^31 - 1) without overflowing 31 bits." x is the value which will eventually be returned (modulo 232) and it is also the next seed. *ctx is the current seed.
16807 is, as the comment says, 75, which is obviously divisible by 7. And 2836 mod 7 is 1. So by the rules of modular arithmetic:
x mod 7 = (16807 * lo) mod 7 - (2836 * hi) mod 7
= 0 - hi mod 7
That value only depends on hi, which is seed / 127773. So hi changes exactly once every 127773 ticks. Since the result of time(NULL) is in seconds, that's one change in 127773 seconds, which is about a day and a half. So if you ran your program once a day, you'd notice that the first random number is sometimes the same as the previous day and sometimes one less. But you're running it quite a bit more often than that, even if you wait a few seconds between runs, so you just see the same first random number every time. Eventually it will tick down and then you'll see a series of 3s instead of 4s.
As mentioned by #rici, the problem is caused by the poor implementation of rand(). The man page for srand() recommends using arc4random() instead. Alternatively, you could try seeding with a value taken directly from /dev/urandom as follows:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int seed;
FILE *f = fopen("/dev/urandom", "r");
fread(&seed, sizeof(int), 1, f);
srand(seed);
fclose(f);
/* Should be a lot more unpredictable: */
printf("%d\n", rand() % 7);
return (0);
}
I am trying to choose one of two numbers randomly: 2 or -2. Is there a way to do it? I am trying to implement an algorithm to create a maze.
You have rand() from the C standard library, which returns a pseudo-random integer in the range [0, RAND_MAX]. You can use this function and choose one of the two numbers checking if the value returned is above or below RAND_MAX/2.
First, use srand() to initialize the pseudo-random number generator with some seed. It's common to use time() to do this as it returns a different value each time.
srand(time(NULL));
int rnd = rand();
int result = (rnd > RAND_MAX/2) ? 2 : -2;
Alternatively you could use the least significant bit of the value returned by rand(), as suggested in this other answer, since half the values returned are odd and half are even:
int result = (rnd & 1) ? 2 : -2;
There are many ways to do this, my favorite is:
a + rand() % 2 * (b - a);
but it isn't clear what does it do and it doesn't contribute on efficiency either (well if you would make it into a macro/inline function and never used with variables, modern compilers should evaluate the numbers at the compile-time), so the most elegant way to do this would be to use some kind of condition, here's an example with ternary operator:
(rand() % 2)? a: b;
BTW: There are many ways to chose between 0/1, I used rand()%2 because it's most the used technique,
but if you happened to be doing this for 6502 architecture where there's no modulo/division you can do it with bitwise-and operator like this rand() & ANY_POWER_OF_TWO or like this rand() > HALF_MAX_RAND
You can use this. It uses bitwise operations to generate either 2 or -2 without branching:
-((rand() & 1) << 2) + 2
I note that you should use srand() to seed the random number generator before using it; I commonly use srand(time(NULL)).
Step-by-step:
(rand() & 1) generates a random number: either 0 or 1.
<< 2 multiplies the previous result by 4, and the - in front of -((rand() & 1) << 2) negates that, so the result is either 0 or -4.
+ 2 adds 2, so the result is either 2 or -2.
If you'd like to see a more arithmetic-like approach that may be easier to follow, here it is:
rand % 2 * -4 + 2
I've been looking into the int rand() function from <stdlib.h> in C11 when I stumbled over the following cppreference-example for rolling a six sided die.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand(time(NULL)); // use current time as seed for random generator
int random_variable = rand();
printf("Random value on [0,%d]: %d\n", RAND_MAX, random_variable);
// roll a 6-sided die 20 times
for (int n=0; n != 20; ++n) {
int x = 7;
while(x > 6)
x = 1 + rand()/((RAND_MAX + 1u)/6); // Note: 1+rand()%6 is biased
printf("%d ", x);
}
}
Specifically this part:
[...]
while(x > 6)
x = 1 + rand()/((RAND_MAX + 1u)/6); // Note: 1+rand()%6 is biased
[...]
Questions:
Why the addition of + 1u? Since rand() is [0,RAND_MAX] I'm guessing
that doing rand()/(RAND_MAX/6) -> [0,RAND_MAX/(RAND_MAX/6)] -> [0,6]? And
since it's integer division (LARGE/(LARGE+small)) < 1 -> 0, adding 1u gives it the required range of [0,5]?
Building on the previous question, assuming [0,5], 1 + (rand()/((RAND_MAX+1u)/6)) should only go through [1,6] and never trigger a second loop?
Been poking around to see if rand() has returned float at some point, but
that seems like a pretty huge breakage towards old code? I guess the check
makes sense if you add 1.0f instead of 1u making it a floating point
division?
Trying to wrap my head around this, have a feeling that I might be missing
something..
(P.s. This is not a basis for anything security critical, I'm just exploring
the standard library. D.s)
The code avoids bias by ensuring each possible result in [1, 6] is the output from exactly the same number of return values from rand.
By definition, rand returns int values from 0 to RAND_MAX. So there are 1+RAND_MAX possible values it can return. If 1+RAND_MAX is not a multiple of 6, then it is impossible to partition it into 6 exactly equal intervals of integers. So the code partitions it into 6 equal intervals that are as big as possible and one odd-size fragment interval. Then the results of rand are mapped into these intervals: The first six intervals correspond to results from 1 to 6, and the last interval is rejected, and the code tries again.
When we divide 1+RAND_MAX by 6, there is some quotient q and some remainder r. Now consider the result of rand() / q:
When rand produces a number in [0, q−1], rand() / q will be 0.
When rand produces a number in [q, 2q−1], rand() / q will be 1.
When rand produces a number in [2q, 3q−1], rand() / q will be 2.
When rand produces a number in [3q, 4q−1], rand() / q will be 3.
When rand produces a number in [4q, 5q−1], rand() / q will be 4.
When rand produces a number in [5q, 6q−1], rand() / q will be 5.
When rand produces a number that is 6q or greater, rand() / q will be 6.
Observe that in each of the first six intervals, there are exactly q numbers. In the seventh interval, the possible return values are in [6q, RAND_MAX]. That interval contains r numbers.
This code works by rejecting that last interval:
int x = 7;
while(x > 6)
x = 1 + rand()/((RAND_MAX + 1u)/6);
Whenever rand produces a number in that last fragmentary interval, this code rejects it and tries again. When rand produces a number in one of the whole intervals, this code accepts it and exits (after adding 1 so the results in x are 1 to 6 instead of 0 to 5).
Thus, every output from 1 to 6, inclusive, is mapped to from an exactly equal number of rand values.
This is the best way to produce a uniform distribution from rand in the sense that it has the fewest rejections, given we are using a scheme like this.1 The range of rand has been split into six intervals that are as big as possible. The remaining fragmentary interval cannot be used because the remainder r is less than six, so the r unused values cannot be split evenly over the six desired values for x.
Footnote
1 This is not necessarily the best way to use rand to generate random numbers in [1, 6] overall. For example, from a single rand call with RAND_MAX equal to 32767, we could view the value as a base-six numeral from 000000 to 411411. If it is under 400000, we can take the last five digits, which are each uniformly distributed in [0, 5], and adding one gts us the desired [1, 6]. If it is in [400000, 410000), we can use the last four digits. If it is in [410000, 411000), we can use the last three, and so on. Additionally, the otherwise discarded information, such as the leading digit, might be pooled over multiple rand calls to increase the average number of outputs we get per call to rand.
my problem this time is not using a line but understanding it,
i received this line from my teacher to randomize a number between the MIN and MAX values, and it works perfectly, but i have tried to understand How exactly and i just couldn't.
I would be happy if anyone could explain it to me step by step (please not i'm not 100% sure how the rand() function works)
Thanks!
int number = (rand() % (DICE_MAX - DICE_MIN +1)) + DICE_MIN; // Randomizing a value between 'DICE_MAX' and 'DICE_MIN' which can be defined on the head of this program.
The function rand() generates a random (well, pseudo-random to be precise) number. The int returned from it has a large range, so you need to scale it to necessary range.
Assuming DICE_MIN to be 1 and DICE_MAX to be 6, you need to generate random integers in the range [1, 6]. There are 6 numbers in the range, and DICE_MAX - DICE_MIN + 1 = 6. So whatever integer you get from rand() the value of rand() % (DICE_MAX - DICE_MIN + 1) will be in the range [0, 5]. Adding the minimum of the required range DICE_MIN to it shifts the range to [1, 6].
This is a very widely practiced technique for generating random numbers in a given range.
rand:
Function: Random number generator.
Include: stdlib.h
syntax: int rand(void);
Return Value: The function rand returns the generated pseudo random number.
Description: The rand function generates an integer between 0 and RAND_MAX (a symbolic constant defined in stdlib.h). standard C states that the value of RAND_MAX must be at least 32767. If rand truly produces integers at random, every number between 0 and RAND_MAX has an equal probability of being chosen each time rand is called.
How it works?
Take an example of rolling a dice (six sided). The remainder operator % is used here in conjugation with rand as :
rand % 6;
to produce integers in the range 0 to 5. This is called scaling. The number 6 is called scaling factor. But, we need to generate number from 1 to 6. Now we shift the range of numbers produced by adding 1 to our result (1 + rand%6).
In general
n = a + rand() % b;
where a is the shifting value (which is equal to the first number in the desired range of consecutive integers, i.e, to lower bound) and b is equal to the width of the desired range of consecutive integers.
In the provided snippet of your's
int number = (rand() % (DICE_MAX - DICE_MIN +1)) + DICE_MIN;
DICE_MAX - DICE_MIN +1 is desired width and DICE_MIN is the shifting value.
Further reading: Using rand().
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;
}
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.
How about this:
int randomGen(int limit)
{
return rand() % limit;
}
/* ... */
int main()
{
srand(time(NULL));
printf("%d", randomGen(2041));
return 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.
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.