-1

So trying to figure out what is special about rand() mod k7 in C. In another post someone said that C rand() uses http://en.wikipedia.org/wiki/Linear_congruential_generator but I don't see what makes (mod k7) k-> scalar special for the algorithm associated to ANSI C.

So I have the following code:

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

void getRand(int* num1, int* num2, int* num3);


int main(int argc, const char * argv[])
{
    int i = 0;
    for (i = 0; i < 100; i++) {

        srand(time(NULL));
        printf("%d\n", rand() % 7 );

        sleep(1);
    }
    return 0;
}

This always prints 3. But if I use any n such that 7 does not divide n, I get a better sequence of first values. Still obviously not random but better then just 3 or some c mod 7 = 3.

I deliberately made the program this way with the seed in the loop to show that the first value always returns 3 regardless of the seed.

Yes I could get random numbers for Xn n > 0 but I want X1 % 7 != X1 % 7 for each Xo.

Thomas
  • 201
  • 1
  • 3
  • 12
  • Set the seed to time only once – Joe DF Jun 27 '14 at 17:59
  • 4
    You should be calling `srand()` only once. – Jesus Ramos Jun 27 '14 at 17:59
  • 3
    Even with the reseed, it still prints a bunch of 3's. I would expect the rand() start value to change every second given time() changes every second, yet it seems not to. srand() apparently isn't that granular. – par Jun 27 '14 at 18:04
  • Where in your posted code are you actually changing the seed? Why don't you post the actual code you are running as the illustrative code, not the code you are not running. – Robert Harvey Jun 27 '14 at 21:35
  • 2
    @RobertHarvey He's changing the seed via `time()` with sleeps. It wasn't obvious at all how they were related. My initial throught was 100 iterations is all gonna complete in under one second so the `time()` will all return the same number. – Mysticial Jun 27 '14 at 21:37
  • @Mysticial: That would be my guess as well. – Robert Harvey Jun 27 '14 at 21:37
  • 1
    I get the following sequence of output using gcc 4.8.2: `6 1 3 6 3 5 1 5 0 2`. I changed the loop to compute only 10 times. – R Sahu Jun 27 '14 at 21:38
  • 2
    I read this, then the meta, then this, then the meta, and _THEN_ I understood the question. I think. The question is why rand()%7 always returns 3 even when seeded with 100 unique times. This question is _very_ unclear. Especially since there's several abbreviations and notations unfamiliar to me: "` if I use any n s.t. !(7|n),`" – Mooing Duck Jun 27 '14 at 21:38
  • @RobertHarvey that is the code, and as Mysticial said I am using a bit of an unorthodox method such as sleep but I wanted it so I could see it occur in a loop rather then have to run the program 100+ times myself, I can edit it with output if you like with various modulus entries, but I felt that if someone was really able to answer this they would copy and paste and tinker with it themselves – Thomas Jun 27 '14 at 21:40
  • @RSahu so may be a compiler thing – Thomas Jun 27 '14 at 21:41
  • 1
    What would be more useful is if you could confirm, on your own hardware, that `time(NULL)` is actually returning *different* values in the loop. – Robert Harvey Jun 27 '14 at 21:41
  • @MooingDuck 7|n means 7 divides n so !(7|n) would mean 7 does not divide n – Thomas Jun 27 '14 at 21:41
  • I think what he means is that it is not immediately clear what `n s.t.` means. Is it the number `n`, *such that?* – Robert Harvey Jun 27 '14 at 21:42
  • @RobertHarvey I assumed it was because again if I use mod 6 lets say I get a X1 = range(1-5) – Thomas Jun 27 '14 at 21:43
  • @RobertHarvey aye yea sorry – Thomas Jun 27 '14 at 21:43
  • 1
    Does `time(NULL)` return different values each time through the loop? – Robert Harvey Jun 27 '14 at 21:43
  • 1
    @ThomasWatters It is most likely a platform/compiler issue. What platform/compiler are you using? – R Sahu Jun 27 '14 at 21:43
  • @RobertHarvey: I also didn't understand `!(7|n)`. I'd probably write that as `n%7 != 0` – Mooing Duck Jun 27 '14 at 21:43
  • 1
    @R Sahu it was ran on XCode which I understand to be compiling with GCC but not sure which version – Thomas Jun 27 '14 at 21:45
  • @RSahu i don't think you answered my original question but at least now I know that somehow its related to the compiler. I wasn't sure if 7 was just some magic number for the algorithm being used and if so someone with the background may be able to answer why 7 was magic in whatever pseodrandom hash was being used. – Thomas Jun 27 '14 at 21:52
  • 1
    Are you, perchance, using Mac OS X 10.9 with Xcode 5? http://stackoverflow.com/questions/20263187/rand-14-only-generates-the-values-6-or-13 – Mooing Duck Jun 27 '14 at 23:16
  • @MooingDuck OS X 10.8.5 with Xcode 5 – Thomas Jun 27 '14 at 23:24
  • @MooingDuck lol so looks like you found the almost duplicate post. Same issue it seems – Thomas Jun 27 '14 at 23:26

1 Answers1

2

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.

Simeon Pilgrim
  • 22,906
  • 3
  • 32
  • 45
  • 1
    Of course, what you're really showing is that this doesn't affect Visual C++'s runtime library. (Based on use of `unistd.h` in the question, I'm almost positive it isn't tested on Windows) – Ben Voigt Jun 27 '14 at 22:45
  • @BenVoigt Yes, I get that also... but my two questions are "so you %7 a rand and get 3 after seeding, SO WHAT?" and "what happens when you test a larger data set" so here's my larger data set code for OP to test. – Simeon Pilgrim Jun 27 '14 at 22:48
  • @SimeonPilgrim first off appreciate you trying to figure this one out for me. Heres my output: code' result: 0 count: 127773 result: 1 count: 127773 result: 2 count: 172736 result: 3 count: 188398 result: 4 count: 127774 result: 5 count: 127773 result: 6 count: 127773 – Thomas Jun 27 '14 at 23:17
  • "Per wikipedia, the multiplier being used in Apple's MCG random number generator is 16807. This is divisible by 7, so the first random number produced after srand() will have only one bit of entropy mod 14 (that is, it can only take on two values)." http://stackoverflow.com/questions/20263187/rand-14-only-generates-the-values-6-or-13 – Mooing Duck Jun 27 '14 at 23:21
  • So why is it so heavy on 2 and 3 – Thomas Jun 27 '14 at 23:21
  • @MooingDuck what does it mean to have one bit of entropy mod 14? – Thomas Jun 27 '14 at 23:22
  • @Thomas so when you run longer you get a more random distribution. Makes me think your see the effects and small change in you seed numbers. – Simeon Pilgrim Jun 27 '14 at 23:31
  • @SimeonPilgrim yes "more" random but still 2 and 3 seem to have a skewed weight in comparison dont you think? – Thomas Jun 27 '14 at 23:35
  • 1
    @thomas. Yes and no. It's a approximation of randomness and as Mooing Duck points out if the modulo used has a 7 as the last digit that explains a lot. So why does this matter? And why are you hung up on %7 the rand results. What are you really trying to here that this is impacting. Or are you nearly point outing that a rand is not crypto safe? – Simeon Pilgrim Jun 27 '14 at 23:41
  • @SimeonPilgrim no no nothing that advance, my buddy has some CS I project "simulating" a slot machine and he asked me why he kept getting a 4 for the first number, he was using rand() % 7 + 1; I was stumped – Thomas Jun 27 '14 at 23:45
  • Maybe then seed once and take and throw away the first 10 results. – Simeon Pilgrim Jun 27 '14 at 23:48
  • 1
    @SimeonPilgrim: or use a different engine, arc4random seems to be what other XCoders are recommending as a workaround. I'm not sure how many results you'd have to discard before subsequent results get 4 bits of entropy. It's even possible that it never happens. – Mooing Duck Jun 27 '14 at 23:50
  • @MooingDuck agreed, but if it a CS program and their slot machine spins a 4 on the first spin. It's not a big issue. Unless they are being tested on real world gaming machine payout behavior regulations adherence. – Simeon Pilgrim Jun 28 '14 at 00:06
  • @SimeonPilgrim: Actually, his prior tests seem to show that it doesn't fully get enough bits ever, since he gets 3 on 18.84% of attempts instead of the expected 14.29%. For homework it's probably fine though – Mooing Duck Jun 28 '14 at 00:18
  • @MooingDuck I'd say it's fit for purpose for must games. Or projects where you just don't want 100 results that are all the same. The mention of entropy get very close to crypto talk at which point it's super not suitable. – Simeon Pilgrim Jun 28 '14 at 00:25
  • @SimeonPilgrim so decided to go back and look at this same problem today and now instead of printing 3 each time it only prints 1, weird stuff – Thomas Jun 30 '14 at 17:27
  • @Thomas no not wired at all do a hundered thousand seed operations and then take first and see a distribution. Yes the first number is correlated to the date, but this rand is not very good. You really need to understand that. But as long as you only seed it once per execution of you program. It will mostly appear random. – Simeon Pilgrim Jun 30 '14 at 19:55