Rand() % 14 Only Generates the Values 6 or 13

Rand() % 14 only generates the values 6 or 13

I can reproduce the problem on Mac OS X 10.9 with Xcode 5 - it looks like it might actually be a bug, or at least a limitation with rand()/srand() on OS X 10.9.

I recommend you use arc4random() instead, which works a lot better than rand(), and which doesn't require that you randomize the seed:

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, const char * argv[])
{
cout << (arc4random() % 14) << endl;
return 0;
}

Test:

$ g++ -Wall -O3 srand.cpp && ./a.out
5
$ ./a.out
8
$ ./a.out
0
$ ./a.out
8
$ ./a.out
11
$ ./a.out
8
$ ./a.out
3
$ ./a.out
13
$ ./a.out
9
$

rand function is giving me the same result at each run even when I called srand(time(NULL))

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.

Same random number every time even after seeding

It appears that this question duplicates this one. Essentially, the issue is a the random number generator is a Linear Congruential Generator.

I can get some better results by xor-ing something changing (like the time) by rand() before mod-ing.

I, for one, have learned from this experience to be even more wary of pseudo-random number generators than I already was.

first rand() generates the same value after srand(time(0))

You are getting the same numbers because the seeds are so close in value and the random generator hasn't had time to diverge yet. On OS X use sranddev() instead of srand(), it will give you a better seed and avoid this problem.

#include<iostream>
using namespace std;

int main()
{
int a, b;

// seed the random number generator
sranddev();

a = rand();
b = rand();

cout << a << " " << (a % 49) + 1 << endl
<< b << " " << (b % 49) + 1 << endl << endl;

return 0;
}

Why is (rand() % anything) always 0 in C++?

The following code works just fine for me (emitting a random number between 0 included and 1000 excluded each time it's run):

#include <cstdlib>
#include <ctime>
#include <iostream>

int main()
{
std::srand(time(0));
std::cout<<(std::rand() % 1000)<<std::endl;
return 0;
}

Can rand() really be this bad?

Have you tried arc4random()? It provides much stronger and more uniform random values than rand().

You could also try SecRandomCopyBytes(), which is part of Security.framework. This basically just reads from /dev/random.

ANSI C / rand() % 7 first value is always 3

Ok, lets start with looking at more than just a few data points:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>


int main(int argc, const char * argv[])
{
size_t counters[7] = {0,0,0,0,0,0,0};
time_t tt = time(NULL);

//for (size_t i = 0; i < 7; i++) {
// printf("result: %d count: %d\n", i, counters[i]);
//}

for (size_t i = 0; i < 1000000; i++) {
srand(tt + i);
counters[rand() % 7] ++;
}

for (size_t i = 0; i < 7; i++) {
printf("result: %d count: %d\n", i, counters[i]);
}
}

with this, on Windows 7, Visual Studio 2013 compile as C++ I get

result: 0 count: 142894
result: 1 count: 142850
result: 2 count: 142848
result: 3 count: 142855
result: 4 count: 142854
result: 5 count: 142845
result: 6 count: 142854

what do you get, because I suspect you'll get a better result from a larger data set.

rand() generating the same number – even with srand(time(NULL)) in my main!

The issue is that the random number generator is being seeded with a values that are very close together - each run of the program only changes the return value of time() by a small amount - maybe 1 second, maybe even none! The rather poor standard random number generator then uses these similar seed values to generate apparently identical initial random numbers. Basically, you need a better initial seed generator than time() and a better random number generator than rand().

The actual looping algorithm used is I think lifted from Accelerated C++ and is intended to produce a better spread of numbers over the required range than say using the mod operator would. But it can't compensate for always being (effectively) given the same seed.

Equivalent of srand() and rand() using post-C++11 std library

You can't even assure that you get the same sequence if you use rand() on another compiler. And no, you can't get random to produce the same sequence as whoever's rand() it was you were using. (Thank goodness. rand() is notorious for being one of the worst pseudo-random number generators of all time.)

It is possible for you to restore the state of rand(), simply by using srand() to set the initial state and counting how many times you called rand(). You can later repeat that to bring rand() back to that same state.

But don't use rand()!

What does the line seed[0] *= 16807 do

seed[0] is same as *seed, that is the first integer (possibly the only one, if it doesn't point to an array) pointed to by seed pointer.

*= operator is "assignment by product" operator,

seed[0] *= 16807; is same as

*seed = *seed * 16807;, which is what the line you ask about does.

The whole function is a simple algorithm to generate pseudo-random numbers, it seems. The purpose of modifying the seed is, that next call will produce a different pseudo-random number.



Related Topics



Leave a reply



Submit