#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
//compile with: gcc -Wall -Wextra cc-c.c -o cc-c
//run with: ./cc-c # no seed given: rand acts as if srand(1) was called
// ./cc-c # run it again: exactly the same numbers
// ./cc-c 42 # seed 42: a different sequence, the same every time
// ./cc-c time # seed from the clock: different on every run
//K&R2 7.8.7 Random Number Generation -- every claim in the section,
//each shown by a line of code and the printf under it:
// 1. rand() gives integers from 0 to RAND_MAX, defined in <stdlib.h>
// 2. frand() = (double) rand() / (RAND_MAX+1.0) is >= 0 and < 1
// (and why each piece of that macro is there)
// 3. a library float generator is likely better: POSIX drand48
// 4. srand(unsigned) sets the seed
// 5. the portable rand/srand from section 2.7, run next to glibc's
//Plus one use: casting a Zhouyi hexagram with the three-coin method.
//the book's macro, as printed
#define frand() ((double) rand() / (RAND_MAX+1.0))
//section 2.7's portable version, renamed: <stdlib.h> already has rand
unsigned long int next = 1;
//kr_rand: return pseudo-random integer on 0..32767
int kr_rand(void)
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
//kr_srand: set seed for kr_rand()
void kr_srand(unsigned int seed)
{
next = seed;
}
int coin(void);
int main(int argc, char *argv[])
{
int i, r;
unsigned seed = 1;
//--- 1. rand: 0 to RAND_MAX --------------------------------------
printf("1. RAND_MAX = %d", RAND_MAX);
printf(RAND_MAX == INT_MAX ? " (= INT_MAX here: glibc uses the whole int range)\n"
: "\n");
printf(" the standard only promises RAND_MAX >= 32767\n");
//no srand yet: the standard says rand then behaves as if srand(1)
printf(" first rand() calls, no srand:");
for (i = 0; i < 3; i++)
printf(" %d", rand());
printf("\n");
srand(1);
printf(" after srand(1): ");
for (i = 0; i < 3; i++)
printf(" %d", rand());
printf(" <- same three\n\n");
//--- 2. frand: >= 0 and < 1 --------------------------------------
printf("2. frand() five times:");
for (i = 0; i < 5; i++)
printf(" %.6f", frand());
printf("\n");
//why (double): without it, int / int throws away the fraction
r = rand();
printf(" without (double): rand() / RAND_MAX = %d / %d = %d (int division)\n",
r, RAND_MAX, r / RAND_MAX);
//why RAND_MAX+1.0 and not RAND_MAX: the biggest rand() would give 1.0
printf(" biggest rand() / RAND_MAX = %.17f <- 1 is NOT < 1\n",
(double) RAND_MAX / RAND_MAX);
printf(" biggest rand() / (RAND_MAX+1.0) = %.17f\n",
(double) RAND_MAX / (RAND_MAX + 1.0));
//why +1.0 and not +1: RAND_MAX+1 is int arithmetic, and here
//RAND_MAX is INT_MAX, so +1 overflows (undefined behaviour; gcc
//wraps it to INT_MIN). +1.0 makes it double arithmetic first.
printf(" RAND_MAX+1.0 = %.1f; RAND_MAX+1 as int would be INT_MAX+1: overflow\n",
RAND_MAX + 1.0);
//frand() * n gives a whole number 0..n-1 after (int) cuts the fraction
printf(" a die, (int)(frand() * 6) + 1:");
for (i = 0; i < 10; i++)
printf(" %d", (int)(frand() * 6) + 1);
printf("\n\n");
//--- 3. a library float generator ---------------------------------
//drand48 (POSIX, not ISO C) returns a double in [0, 1) directly,
//from its own 48-bit state -- the "better statistical properties"
//the book means: frand's double holds only rand()'s 31 bits
srand48(1);
printf("3. drand48() three times:");
for (i = 0; i < 3; i++)
printf(" %.17f", drand48());
printf("\n\n");
//--- 4. srand(unsigned) sets the seed ------------------------------
//IDIOM: argc > 1 && ... -- the && guard: read argv[1] only if it exists
if (argc > 1 && argv[1][0] == 't')
//IDIOM: srand(time(NULL)) -- the usual seed: the clock in
//seconds, so each run (a second apart) starts somewhere new
seed = (unsigned) time(NULL);
else if (argc > 1)
seed = (unsigned) atoi(argv[1]);
srand(seed);
printf("4. srand(%u) first:", seed);
for (i = 0; i < 3; i++)
printf(" %d", rand());
printf("\n srand(%u) again:", seed);
srand(seed);
for (i = 0; i < 3; i++)
printf(" %d", rand());
printf(" <- same seed, same sequence\n\n");
//--- 5. section 2.7's portable rand --------------------------------
kr_srand(seed);
printf("5. kr_rand() after kr_srand(%u):", seed);
for (i = 0; i < 5; i++)
printf(" %d", kr_rand());
printf("\n range 0..32767 only -- the standard's minimum RAND_MAX;\n"
" glibc's rand is a different, bigger generator, so its\n"
" numbers above don't match these even with the same seed\n\n");
//--- a use: casting a hexagram --------------------------------------
//three coins per line: heads 3, tails 2, so a line sums to 6..9
// 6 old yin -x- (changing) 7 young yang ---
// 8 young yin - - 9 old yang -o- (changing)
//lines are cast bottom (line 1) to top, and printed top down
srand(seed);
int lines[6];
for (i = 0; i < 6; i++)
lines[i] = coin() + coin() + coin();
printf("three-coin cast, seed %u (top line first):\n", seed);
for (i = 5; i >= 0; i--) {
const char *draw[] = { "-x-", "---", "- -", "-o-" };
printf(" line %d: %d %s\n", i + 1, lines[i], draw[lines[i] - 6]);
}
return 0;
}
//coin: toss one coin with frand: heads 3, tails 2
int coin(void)
{
//IDIOM: frand() < 0.5 -- a fair yes/no; uses the whole value
//rather than rand() % 2, which reads only the lowest bit
return frand() < 0.5 ? 3 : 2;
}
win@DESKTOP-MEIH88T:~/webdev-projects$ gcc -Wall -Wextra cc-c.c -o cc-c
win@DESKTOP-MEIH88T:~/webdev-projects$ ./cc-c
1. RAND_MAX = 2147483647 (= INT_MAX here: glibc uses the whole int range)
the standard only promises RAND_MAX >= 32767
first rand() calls, no srand: 1804289383 846930886 1681692777
after srand(1): 1804289383 846930886 1681692777 <- same three
2. frand() five times: 0.798440 0.911647 0.197551 0.335223 0.768230
without (double): rand() / RAND_MAX = 596516649 / 2147483647 = 0 (int division)
biggest rand() / RAND_MAX = 1.00000000000000000 <- 1 is NOT < 1
biggest rand() / (RAND_MAX+1.0) = 0.99999999953433871
RAND_MAX+1.0 = 2147483648.0; RAND_MAX+1 as int would be INT_MAX+1: overflow
a die, (int)(frand() * 6) + 1: 4 3 4 3 4 6 6 4 5 1
3. drand48() three times: 0.04163034477187821 0.45449244472862915 0.83481721816691490
4. srand(1) first: 1804289383 846930886 1681692777
srand(1) again: 1804289383 846930886 1681692777 <- same seed, same sequence
5. kr_rand() after kr_srand(1): 16838 5758 10113 17515 31051
range 0..32767 only -- the standard's minimum RAND_MAX;
glibc's rand is a different, bigger generator, so its
numbers above don't match these even with the same seed
three-coin cast, seed 1 (top line first):
line 6: 6 -x-
line 5: 7 ---
line 4: 7 ---
line 3: 8 - -
line 2: 7 ---
line 1: 7 ---
win@DESKTOP-MEIH88T:~/webdev-projects$ ./cc-c
1. RAND_MAX = 2147483647 (= INT_MAX here: glibc uses the whole int range)
the standard only promises RAND_MAX >= 32767
first rand() calls, no srand: 1804289383 846930886 1681692777
after srand(1): 1804289383 846930886 1681692777 <- same three
2. frand() five times: 0.798440 0.911647 0.197551 0.335223 0.768230
without (double): rand() / RAND_MAX = 596516649 / 2147483647 = 0 (int division)
biggest rand() / RAND_MAX = 1.00000000000000000 <- 1 is NOT < 1
biggest rand() / (RAND_MAX+1.0) = 0.99999999953433871
RAND_MAX+1.0 = 2147483648.0; RAND_MAX+1 as int would be INT_MAX+1: overflow
a die, (int)(frand() * 6) + 1: 4 3 4 3 4 6 6 4 5 1
3. drand48() three times: 0.04163034477187821 0.45449244472862915 0.83481721816691490
4. srand(1) first: 1804289383 846930886 1681692777
srand(1) again: 1804289383 846930886 1681692777 <- same seed, same sequence
5. kr_rand() after kr_srand(1): 16838 5758 10113 17515 31051
range 0..32767 only -- the standard's minimum RAND_MAX;
glibc's rand is a different, bigger generator, so its
numbers above don't match these even with the same seed
three-coin cast, seed 1 (top line first):
line 6: 6 -x-
line 5: 7 ---
line 4: 7 ---
line 3: 8 - -
line 2: 7 ---
line 1: 7 ---
win@DESKTOP-MEIH88T:~/webdev-projects$ ./cc-c 42
1. RAND_MAX = 2147483647 (= INT_MAX here: glibc uses the whole int range)
the standard only promises RAND_MAX >= 32767
first rand() calls, no srand: 1804289383 846930886 1681692777
after srand(1): 1804289383 846930886 1681692777 <- same three
2. frand() five times: 0.798440 0.911647 0.197551 0.335223 0.768230
without (double): rand() / RAND_MAX = 596516649 / 2147483647 = 0 (int division)
biggest rand() / RAND_MAX = 1.00000000000000000 <- 1 is NOT < 1
biggest rand() / (RAND_MAX+1.0) = 0.99999999953433871
RAND_MAX+1.0 = 2147483648.0; RAND_MAX+1 as int would be INT_MAX+1: overflow
a die, (int)(frand() * 6) + 1: 4 3 4 3 4 6 6 4 5 1
3. drand48() three times: 0.04163034477187821 0.45449244472862915 0.83481721816691490
4. srand(42) first: 71876166 708592740 1483128881
srand(42) again: 71876166 708592740 1483128881 <- same seed, same sequence
5. kr_rand() after kr_srand(42): 19081 17033 15269 25461 13856
range 0..32767 only -- the standard's minimum RAND_MAX;
glibc's rand is a different, bigger generator, so its
numbers above don't match these even with the same seed
three-coin cast, seed 42 (top line first):
line 6: 7 ---
line 5: 9 -o-
line 4: 8 - -
line 3: 7 ---
line 2: 9 -o-
line 1: 8 - -
win@DESKTOP-MEIH88T:~/webdev-projects$ ./cc-c time
1. RAND_MAX = 2147483647 (= INT_MAX here: glibc uses the whole int range)
the standard only promises RAND_MAX >= 32767
first rand() calls, no srand: 1804289383 846930886 1681692777
after srand(1): 1804289383 846930886 1681692777 <- same three
2. frand() five times: 0.798440 0.911647 0.197551 0.335223 0.768230
without (double): rand() / RAND_MAX = 596516649 / 2147483647 = 0 (int division)
biggest rand() / RAND_MAX = 1.00000000000000000 <- 1 is NOT < 1
biggest rand() / (RAND_MAX+1.0) = 0.99999999953433871
RAND_MAX+1.0 = 2147483648.0; RAND_MAX+1 as int would be INT_MAX+1: overflow
a die, (int)(frand() * 6) + 1: 4 3 4 3 4 6 6 4 5 1
3. drand48() three times: 0.04163034477187821 0.45449244472862915 0.83481721816691490
4. srand(1792192586) first: 1110961151 1820287451 1373220166
srand(1792192586) again: 1110961151 1820287451 1373220166 <- same seed, same sequence
5. kr_rand() after kr_srand(1792192586): 20647 1318 31635 24979 4093
range 0..32767 only -- the standard's minimum RAND_MAX;
glibc's rand is a different, bigger generator, so its
numbers above don't match these even with the same seed
three-coin cast, seed 1792192586 (top line first):
line 6: 8 - -
line 5: 7 ---
line 4: 7 ---
line 3: 8 - -
line 2: 7 ---
line 1: 6 -x-