0

Here we have a piece of c code that goes into a dead loop, reading the current timestamp and resetting the random seed each time, after which it prints a random number and sleeps for one second. The seeds are consecutive, and Windows generates the first random number consecutively for consecutive seeds, which is not the case with Linux.

Many languages written in c that don't have their own implementation of a random number generator also have this problem, e.g. lua 5.1

#include<time.h>
#include<stdlib.h>
#include<stdio.h>
#ifdef __linux__
#include <unistd.h>
#else
#include <windows.h>
#endif

void printRandoms(int lower, int upper,
                            int count)
{
    int i;
    for (i = 0; i < count; i++) {
        int num = (rand() %
        (upper - lower + 1)) + lower;
        printf("%d\n", num);
    }
}

int main(){
    while(1){
        srand(time(NULL));
        printRandoms(1,10000,1);
        #ifdef __linux__
        sleep(1);
        #else
        Sleep(1000);
        #endif
    }
    return 0;
}

The output:

On Windows:
I tried both gcc and clang.
1. gcc.exe (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders) 13.1.0
2. (built by Brecht Sanders) clang version 16.0.5
3. gcc.exe (MinGW-W64 x86_64-msvcrt-posix-seh, built by Brecht Sanders) 9.5.0
5237
5238
5239
5240
5241
5242
5243
5245
5246
5247
5248

On Linux:
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
5142
3660
7270
896
9500
3041
6659
5194
8809
7361
5960

I know that's usually the wrong way to use srand(), but was just curious what led to the difference.

Bubbleioa
  • 3
  • 1
  • 1
    There's no requirement that two different libc implementations provide the same random number generator. Your evidence looks like Windows is much more predictable based on seed value than Linux, but that's a perfectly legal (if questionable) implementation. – Stephen Newell Jul 13 '23 at 05:29
  • Different implementations of the random number generator. I believe `RAND_MAX` is different on both which requires different code. – Retired Ninja Jul 13 '23 at 05:29
  • 1
    How precise is the sleep? Wouldn't it be more consistent to seed on a more predictable value than the time after a sleep? – MB-F Jul 13 '23 at 05:31
  • 3
    I'd spin in a busy loop waiting for the value to change instead of sleep. But you don't even need to do that, just call `time(NULL)` once, save the value, and increment it to pass to `srand`. – Retired Ninja Jul 13 '23 at 05:34

2 Answers2

4

You seem to think time( NULL ) is a strong seed, but it's not. While the Linux version looks more random, it's not. It's just as predictable as the Windows version. That's because it's often possible to guess them time of seeding. And knowing that gives the stream of numbers, in both versions. (Even if you don't know the exact time, you just have a few possibilities of streams.) srand should be given a value as random as possible.


The Windows version appears to return the seed as its first value. After all, you should have provided a random value to srand. The Linux one skips returning the seed and starts with the value that follows the seed. As such, you can replicate the behaviour of the Linux rand by calling rand after calling srand.

srand(time(NULL));
(void)rand();
printRandoms(1,10000,1);

This will make the Windows code look just as unpredictable as the Linux version looks.


Note that it doesn't make sense to call srand with a random seed multiple times in a row.

Note that rand should not be used anywhere where randomness is important (e.g. crpytography). Use a proper source of randomness for that.

ikegami
  • 367,544
  • 15
  • 269
  • 518
2

As C's rand(), srand(), RAND_MAX are not specified to be very good for random number generation, some compilers choose a very weak and simple implementation. I suspect it is in order to be compliant yet encourage better alternatives.

MinGW-W64 x86_64 appears to be that way.


Historically there have been very weak implementations. To make your code portable and robust, there is no standard C library solution in 2023. One needs to research for a random number library that meets your goals.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256