3d24943e0e9a3d960fa6264341999f6128712f3e
[xscreensaver] / utils / yarandom.c
1 /* yarandom.c -- Yet Another Random Number Generator.
2
3    The unportable mess that is rand(), random(), drand48() and friends led me
4    to ask Phil Karlton <karlton@netscape.com> what the Right Thing to Do was.
5    He responded with this.  It is non-cryptographically secure, reasonably
6    random (more so than anything that is in any C library), and very fast.
7
8    I don't understand how it works at all, but he says "look at Knuth,
9    Vol. 2 (original edition), page 26, Algorithm A.  In this case n=55,
10    k=20 and m=2^32."
11
12    So there you have it.
13
14    ---------------------------
15    Note: xlockmore 4.03a10 uses this very simple RNG:
16
17         if ((seed = seed % 44488 * 48271 - seed / 44488 * 3399) < 0)
18           seed += 2147483647;
19         return seed-1;
20
21    of which it says
22
23         ``Dr. Park's algorithm published in the Oct. '88 ACM  "Random Number
24           Generators: Good Ones Are Hard To Find" His version available at
25           ftp://cs.wm.edu/pub/rngs.tar Present form by many authors.''
26
27    Karlton says: ``the usual problem with that kind of RNG turns out to
28    be unexepected short cycles for some word lengths.''
29
30    Karlton's RNG is faster, since it does three adds and two stores, while the
31    xlockmore RNG does two multiplies, two divides, three adds, and one store.
32
33    Compiler optimizations make a big difference here:
34        gcc -O:     difference is 1.2x.
35        gcc -O2:    difference is 1.4x.
36        gcc -O3:    difference is 1.5x.
37        SGI cc -O:  difference is 2.4x.
38        SGI cc -O2: difference is 2.4x.
39        SGI cc -O3: difference is 5.1x.
40    Irix 6.2; Indy r5k; SGI cc version 6; gcc version 2.7.2.1.
41  */
42
43
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
47
48 #ifdef HAVE_UNISTD_H
49 # include <unistd.h>  /* for getpid() */
50 #endif
51 #include <sys/time.h> /* for gettimeofday() */
52
53 #include "yarandom.h"
54 # undef ya_rand_init
55
56
57 /* The following 'random' numbers are taken from CRC, 18th Edition, page 622.
58    Each array element was taken from the corresponding line in the table,
59    except that a[0] was from line 100. 8s and 9s in the table were simply
60    skipped. The high order digit was taken mod 4.
61  */
62 #define VectorSize 55
63 static unsigned int a[VectorSize] = {
64  035340171546, 010401501101, 022364657325, 024130436022, 002167303062, /*  5 */
65  037570375137, 037210607110, 016272055420, 023011770546, 017143426366, /* 10 */
66  014753657433, 021657231332, 023553406142, 004236526362, 010365611275, /* 14 */
67  007117336710, 011051276551, 002362132524, 001011540233, 012162531646, /* 20 */
68  007056762337, 006631245521, 014164542224, 032633236305, 023342700176, /* 25 */
69  002433062234, 015257225043, 026762051606, 000742573230, 005366042132, /* 30 */
70  012126416411, 000520471171, 000725646277, 020116577576, 025765742604, /* 35 */
71  007633473735, 015674255275, 017555634041, 006503154145, 021576344247, /* 40 */
72  014577627653, 002707523333, 034146376720, 030060227734, 013765414060, /* 45 */
73  036072251540, 007255221037, 024364674123, 006200353166, 010126373326, /* 50 */
74  015664104320, 016401041535, 016215305520, 033115351014, 017411670323  /* 55 */
75 };
76
77 static int i1, i2;
78
79 unsigned int
80 ya_random (void)
81 {
82   register int ret = a[i1] + a[i2];
83   a[i1] = ret;
84   if (++i1 >= VectorSize) i1 = 0;
85   if (++i2 >= VectorSize) i2 = 0;
86   return ret;
87 }
88
89 void
90 ya_rand_init(unsigned int seed)
91 {
92   int i;
93   if (seed == 0)
94     {
95       struct timeval tp;
96 #ifdef GETTIMEOFDAY_TWO_ARGS
97       struct timezone tzp;
98       gettimeofday(&tp, &tzp);
99 #else
100       gettimeofday(&tp);
101 #endif
102       /* ignore overflow */
103       seed = (999*tp.tv_sec) + (1001*tp.tv_usec) + (1003 * getpid());
104     }
105
106   a[0] += seed;
107   for (i = 1; i < VectorSize; i++)
108     {
109       seed = a[i-1]*1001 + seed*999;
110       a[i] += seed;
111     }
112
113   i1 = a[0] % VectorSize;
114   i2 = (i1 + 024) % VectorSize;
115 }