Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my C code only generating every third random number?

I am trying to simulate the propagation of a worm across a network made of 100,000 computers. The simulation itself is very simple and I don't need any help except that for some reason, I am only getting every third random number.

Only the computers whose index modulo 1000 is less than 10 can be infected so when 1000 computers are infected, the program should be done. For some reason, my program only gets 329. When I lower the goal number and check the contents of the array, only every third computer has been changed and it is a consistent pattern. For example at the end of the array, only computers 98001, 98004, 98007, 99002, 99005, 99008 are changed even though the computers in between (98002, 98003, etc.) should be changed as well. The pattern holds all the way to the beginning of the array. When I try to get all 1000 changed, the program goes into an infinite loop and is stuck at 329.

Edit: I just discovered that if I lower the NETSIZE to 10,000 and the goal in the while loop to 100, it doesn't skip anything. Does that mean the problem has something to do with a rounding error? Someone who knows more about C than me must know the answer.

Thanks.

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

#define NETSIZE 100000

double rand01();
void initNetwork();

unsigned char network[NETSIZE];
int scanrate = 3;
int infectedCount;
int scans;
int ind;
int time;



int main(void) {
    initNetwork();
    time = 0;
    infectedCount = 1;
    while (infectedCount < 1000) { //changing 1000 to 329 stops the infinite loop
        scans = infectedCount * scanrate;
        for (int j = 0; j < scans; j++) {
            ind = (int) (rand01() * NETSIZE);
            if (network[ind] == 0) {
                network[ind] = 1;
                infectedCount++;
            }
        }
        time++;
    }
    for (int k = 0; k < NETSIZE; k++) {
        if (network[k] == 1) printf("%d at %d\n", network[k], k);
    }
}
double rand01() {
    double temp;
    temp = (rand() + 0.1) / (RAND_MAX + 1.0);
    return temp;
}

void initNetwork() {
    for (int i = 0; i < NETSIZE; i++) {
        if (i % 1000 < 10) {
            network[i] = 0;
        } else  {
            network[i] = 2;
        }
    }
    network[1000] = 1;
}

In the above code, I expect the code to run until the 1000 vulnerable indexes are changed from 0 to 1.

like image 326
OpticalFlow Avatar asked Dec 07 '25 19:12

OpticalFlow


1 Answers

Converting comments into an answer.

What is RAND_MAX on your system? If it is a 15-bit or 16-bit value, you probably aren't getting good enough quantization when converted to double. If it is a 31-bit or bigger number, that (probably) won't be the issue. You need to investigate what values are generated by just the rand01() function with different seeds, plus the multiplication and cast to integer — simply print the results and sort -n | uniq -c to see how uniform the results are.

On my system RAND_MAX is only 32767. Do you think that might be why my results might not be granular enough? Now that you've made me think about it, there would only be 32,767 possible values and my network array is 100,000 possible values. Which corresponds about about the 1/3 results I am getting.

Yes, I think that is very probably the problem. You want 100,000 different values, but your random number generator can only generate about 33,000 different values, which is awfully close to your 1:3 metric. It also explains immediately why you got good results when you reduced the multiplier from 100,000 to 10,000.

You could try:

double rand01(void)
{
    assert(RAND_MAX == 32767);
    return ((rand() << 15) + rand()) / ((RAND_MAX + 1.0) * (RAND_MAX + 1.0));
}

Or you could use an alternative random number generator — for example, POSIX defines both the drand48() family of functions and random(), with corresponding seed-setting functions where needed.

like image 75
Jonathan Leffler Avatar answered Dec 09 '25 15:12

Jonathan Leffler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!