Skip to content

Instantly share code, notes, and snippets.

@antirez
Last active March 13, 2017 19:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antirez/52529aefb7000aa076f5fc6675252c3c to your computer and use it in GitHub Desktop.
Save antirez/52529aefb7000aa076f5fc6675252c3c to your computer and use it in GitHub Desktop.
/* MacOS libc PRNG is garbage!
* Test this on MacOS 10.12.3 (may be the same with other versions)
* You'll see three times the same output.
* Cheers by @antirez. */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* Note, 1000000, 1000001, 1000002 are not special.
* You can use any other "near" seeds and MOD 7 the sequence will be the same. */
srand(1000000);
printf("%d\n", rand() % 7);
srand(1000001);
printf("%d\n", rand() % 7);
srand(1000002);
printf("%d\n", rand() % 7);
return 0;
}
@dchest
Copy link

dchest commented Mar 13, 2017

Copying here from my twitter:

This isn’t a proper test for “weak” PRNG — you’re supposed to be seeding it once and then extracting random numbers. You just found a case where different initial seeds produce same outputs, but rand() doesn’t guarantee that it should produce different outputs in such case: it only guarantees that same srand() seed produces same sequence. If your seeds are pseudorandom — not related — rand() will likely produce what you expect (there’s sranddev(), which sets seed to a pseudorandom value). This is still not good, of course: rand(), random(), etc. are all old, bad PRNGs anyway on many systems.

BTW, OpenBSD replaced all those crappy libc PRNGs with one good cryptographically secure PRNG.

@colmmacc
Copy link

colmmacc commented Mar 13, 2017

Is this post satire? with an unbiased PRNG there will be a subsequence of three 0's like this in every 7^3 (343) sequence of seeds. 6 more if you're willing to accept a subsequence of any particular digit. Also this isn't an unbiased test. rand() % 7 will bias slightly in favor of the value 0 because RAND_MAX isn't a whole multiple of 7.

sigh. I missed the comment, and only read the code. It does look like rand() on Mac has some kind of internal periodicity. Which is bad.

@ChrisMcKee
Copy link

ChrisMcKee commented Mar 13, 2017

^ makes sense.

using the first seed gives

4
1
1
3
0

or

21585
18586
29373
4301
3304

without the modulus

every time.

Less a bug, more an intended, but sucky, feature.

@antirez
Copy link
Author

antirez commented Mar 13, 2017

There is some confusion here about crypto-PRNG, my example above, which is not limited to the seeds I selected, and so forth. So:

  1. The problem is not that the rand() sequence is deterministic. Here I'm not even checking that its distribution is random-looking.
  2. The special seeds I wrote above are just examples, the % 7 same results for different X, X+1, X+2 seeds will happen for almost all the seeds.
  3. It is trivial to have a fast PRNG that provides a decent distribution, and that by changing the seed produces a very different sequence.
  4. My claim is documented in the implementation itself... so the code acknowledges it.
  5. srand(time(NULL)) is a huge programming pattern to just say: give me a different sequence every different second I run it.

@antirez
Copy link
Author

antirez commented Mar 13, 2017

@colmmacc read my last post. You misunderstood the point completely. Happens for every possible N seeds that are just similar numbers.

@antirez
Copy link
Author

antirez commented Mar 13, 2017

TLDR: it happens even with this code.

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

int main(void) {
    int seed = time(NULL);
    srand(seed+1);
    printf("%d\n", rand() % 7);
    srand(seed+2);
    printf("%d\n", rand() % 7);
    srand(seed+10);
    printf("%d\n", rand() % 7);
    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment