I have a function that should initialize the values of matrix in a random way, given a probability (in this case p(0)=1/3, p(1) = 2/3 )
The problem is that the matrix always comes out to be the same:
void init_matrix(short unsigned* m,int* n_gen)
{
*n_gen=0;
int i;
for(i=0;i<N_X*N_Y;i++) {
if( ( ( rand() % 100 ) % 3) == 0 )
m[i]=0;
else
m[i]=1;
}
}
is it because of the implementation of the rand() function? Or am I using it incorrectly? Thanks!
You should call srand function to initialize random number generator:
srand(time(NULL));
init_matrix(m, &n_gen); // call your function
For every value passed as argument rand() generates a different succession.
You need to call srand in the initial section of your code in order to initialize your random number generator, as the document shows this is typical ways of calling srand:
srand(time(0));
as the document explains:
If rand() is used before any calls to srand(), rand() behaves as if it was seeded with srand(1). Each time rand() is seeded with srand(), it must produce the same sequence of values.
and this part explains why we use time(0):
Standard practice is to use the result of a call to time(0) as the seed. However, time() returns a time_t value, and time_t is not guaranteed to be an integral type. In practice, though, every major implementation defines time_t to be an integral type, and this is also what POSIX requires.
Related
I'm trying to generate a random-number sequence with rand().
I have something like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int Random(int min, int max)
{
/* returns a random integer in [min, max] */
double uniform; // random variable from uniform distribution of [0, 1]
int ret; // return value
srand((unsigned int)clock());
uniform = rand() / (double)RAND_MAX;
ret = (int)(uniform * (double)(max - min)) + min;
return ret;
}
int main(void)
{
for(int i=0; i<10; i++)
printf("%d ", Random(0, 100));
printf("\n");
return 0;
}
It made different results when executed on macOS v10.14 (Mojave) and Ubuntu 18.04 (Bionic Beaver).
It works on Ubuntu:
76 42 13 49 85 7 43 28 15 1
But not on macOS:
1 1 1 1 1 1 1 1 1 1
Why doesn't it work well on macOS? Is there something different in random number generators?
I'm a Mac user. To generate random numbers I initialise the seed like this:
srand(time(NULL));
Plus, try initialising it in your main.
If reproducible "random" numbers are something you care about, you should avoid the rand function. The C standard doesn't specify exactly what the sequence produced by rand is, even if the seed is given via srand. Notably:
rand uses an unspecified random number algorithm, and that algorithm can differ between C implementations, including versions of the same standard library.
rand returns values no greater than RAND_MAX, and RAND_MAX can differ between C implementations.
Instead, you should use an implementation of a pseudorandom number generator with a known algorithm, and you should also rely on your own way to transform pseudorandom numbers from that algorithm into the numbers you desire. (For many ways to do so, see my page on sampling algorithms. Note that there are other things to consider when reproducibility is important.)
See also the following:
Does Python have a function to mimic the sequence of C's rand()?
Why is the use of rand() considered bad?
How predictable is the result of rand() between individual systems?
rand is obsolete in Mac. Use random() instead.
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.
This question already has answers here:
What‘s the difference between srand(1) and srand(0)
(7 answers)
Closed 8 years ago.
srand(0) and srand(1) give the same results. srand(2), srand(3), etc. give different results.
Any reason why seed = 0 and seed = 1 yield the same random sequence?
Can't find an explanation in the man page. Only that if a seed is not provided, seed = 1 is used.
Thanks.
Within the glibc sources for srandom_r (which is aliased to srand), line 179:
/* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */
if (seed == 0)
seed = 1;
It's just an arbitrary decision basically.
Depends on compiler!
srand(0);
int a=rand(),b=rand();
srand(1);
int c=rand(),d=rand();
VC 2005 result:
a 0x00000026 int
b 0x00001e27 int
c 0x00000029 int
d 0x00004823 int
This is an implementation dependent behaviour.
For instance, POSIX.1-2001 gives the following example of an implementation of rand() and srand()
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
Now, if you use this implementation you will end up with:
0
16838
for srand(0) and srand(1) respectively.
ref.:
http://linux.die.net/man/3/rand
I ran into a quite similar problem before, where rand() yielded different sequences for the same seed across different platforms. Lesson learned, portable code should implement his own PRNG.
The function srand() is used to initialize the pseudo-random number generator by passing the argument seed.
So if the seed is set to 1 then the generator is reinitialized to its initial value. Then it will produce the results as before any call to rand and srand.
so srand(1) actually represent the result srand(0).
I understand that what's passed into srand() as an argument will be used as the seed for calls to rand() that happen afterward. Generally time(NULL) is passed in.
But if you only call srand once, and then you have rand being called continuously in a loop, how are the numbers different from each other? The seed was the value returned from time(NULL)...but ONLY that one specific return value is being used. So how are different numbers being generated?
I don't know anything about threading in C. But is srand using threads and a different seed each time so that subsequent calls to rand actually do return random numbers? I noticed that when I pass a static number to srand instead of time(NULL), the rand is still generating random numbers.
The draft C99 standard provides a sample implementation in section 7.20.2.2 The srand function that will probably clear up how it work for you:
EXAMPLE The following functions define a portable implementation of rand and srand.
static unsigned long int next = 1;
int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
void srand(unsigned int seed)
{
next = seed;
}
srand set the static variable next which is then set to new value in rand and then subsequent calls to rand will pick up with the previous value of next.
For example if we used srand(1) then the sequence would look like this as we make calls to rand:
next = 1
next = 1 * 1103515245 + 12345 = 1103527590
next = 1103527590 * 1103515245 + 12345 = 1217759518843121895
next = 1217759518843121895 * 1103515245 + 12345 = 15426401326682203284
As HostileFork points out, the numbers are not truly random but are Pseudorandom, which says:
also known as a deterministic random bit generator (DRBG),[1] is an
algorithm for generating a sequence of numbers whose properties
approximate the properties of sequences of random numbers. The
PRNG-generated sequence is not truly random, because it is completely
determined by a relatively small set of initial values, called the
PRNG's seed (which may include truly random values). Although
sequences that are closer to truly random can be generated using
hardware random number generators, pseudorandom number generators are
important in practice for their speed in number generation and their
reproducibility.
This particular implementation is using a Linear congruential generator.
I've written a C function that I think selects integers from a uniform distribution with range [rangeLow, rangeHigh], inclusive. This isn't homework--I'm just using this in some embedded systems tinkering that I'm doing for fun.
In my test cases, this code appears to produce an appropriate distribution. I'm not feeling fully confident that the implementation is correct, though.
Could someone do a sanity check and let me know if I've done anything wrong here?
//uniform_distribution returns an INTEGER in [rangeLow, rangeHigh], inclusive.
int uniform_distribution(int rangeLow, int rangeHigh)
{
int myRand = (int)rand();
int range = rangeHigh - rangeLow + 1; //+1 makes it [rangeLow, rangeHigh], inclusive.
int myRand_scaled = (myRand % range) + rangeLow;
return myRand_scaled;
}
//note: make sure rand() was already initialized using srand()
P.S. I searched for other questions like this. However, it was hard to filter out the small subset of questions that discuss random integers instead of random floating-point numbers.
Let's assume that rand() generates a uniformly-distributed value I in the range [0..RAND_MAX],
and you want to generate a uniformly-distributed value O in the range [L,H].
Suppose I in is the range [0..32767] and O is in the range [0..2].
According to your suggested method, O= I%3. Note that in the given range, there are 10923 numbers for which I%3=0, 10923 number for which I%3=1, but only 10922 number for which I%3=2. Hence your method will not map a value from I into O uniformly.
As another example, suppose O is in the range [0..32766].
According to your suggested method, O=I%32767. Now you'll get O=0 for both I=0 and I=32767. Hence 0 is twice as likely than any other value - your method is again nonuniform.
The suggest way to generate a uniform mapping is as follow:
Calculate the number of bits that are needed to store a random value in the range [L,H]:
unsigned int nRange = (unsigned int)H - (unsigned int)L + 1;
unsigned int nRangeBits= (unsigned int)ceil(log((double(nRange) / log(2.));
Generate nRangeBits random bits
this can be easily implemented by shifting-right the result of rand()
Ensure that the generated number is not greater than H-L.
If it is - repeat step 2.
Now you can map the generated number into O just by adding a L.
On some implementations, rand() did not provide good randomness on its lower order bits, so the modulus operator would not provide very random results. If you find that to be the case, you could try this instead:
int uniform_distribution(int rangeLow, int rangeHigh) {
double myRand = rand()/(1.0 + RAND_MAX);
int range = rangeHigh - rangeLow + 1;
int myRand_scaled = (myRand * range) + rangeLow;
return myRand_scaled;
}
Using rand() this way will produce a bias as noted by Lior. But, the technique is fine if you can find a uniform number generator to calculate myRand. One possible candidate would be drand48(). This will greatly reduce the amount of bias to something that would be very difficult to detect.
However, if you need something cryptographically secure, you should use an algorithm outlined in Lior's answer, assuming your rand() is itself cryptographically secure (the default one is probably not, so you would need to find one). Below is a simplified implementation of what Lior described. Instead of counting bits, we assume the range falls within RAND_MAX, and compute a suitable multiple. Worst case, the algorithm ends up calling the random number generator twice on average per request for a number in the range.
int uniform_distribution_secure(int rangeLow, int rangeHigh) {
int range = rangeHigh - rangeLow + 1;
int secureMax = RAND_MAX - RAND_MAX % range;
int x;
do x = secure_rand(); while (x >= secureMax);
return rangeLow + x % range;
}
I think it is known that rand() is not very good. It just depends on how good of "random" data you need.
http://www.azillionmonkeys.com/qed/random.html
http://www.linuxquestions.org/questions/programming-9/generating-random-numbers-in-c-378358/
http://forums.indiegamer.com/showthread.php?9460-Using-C-rand%28%29-isn-t-as-bad-as-previously-thought
I suppose you could write a test then calculate the chi-squared value to see how good your uniform generator is:
http://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test
Depending on your use (don't use this for your online poker shuffler), you might consider a LFSR
http://en.wikipedia.org/wiki/Linear_feedback_shift_register
It may be faster, if you just want some psuedo-random output. Also, supposedly they can be uniform, although I haven't studied the math enough to back up that claim.
A version which corrects the distribution errors (noted by Lior),
involves the high-bits returned by rand() and
only uses integer math (if that's desirable):
int uniform_distribution(int rangeLow, int rangeHigh)
{
int range = rangeHigh - rangeLow + 1; //+1 makes it [rangeLow, rangeHigh], inclusive.
int copies=RAND_MAX/range; // we can fit n-copies of [0...range-1] into RAND_MAX
// Use rejection sampling to avoid distribution errors
int limit=range*copies;
int myRand=-1;
while( myRand<0 || myRand>=limit){
myRand=rand();
}
return myRand/copies+rangeLow; // note that this involves the high-bits
}
//note: make sure rand() was already initialized using srand()
This should work well provided that range is much smaller than RAND_MAX, otherwise
you'll be back to the problem that rand() isn't a good random number generator in terms of its low-bits.