1/*
2 * RANDOM.C -- Implements Park & Miller's "Minimum Standard" RNG
3 *
4 * (Reference: CACM, Oct 1988, pp 1192-1201)
5 *
6 * NextRand: Computes next random integer
7 * UnifInt: Yields an long uniformly distributed between given bounds
8 * UnifReal: ields a real uniformly distributed between given bounds
9 * Exponential: Yields a real exponentially distributed with given mean
10 *
11 */
12
13#include "config.h"
14
15#include <math.h>
16#include <stdio.h>
17#include <stdint.h>
18#include "dss.h"
19#include "rnd.h"
20
21const char *env_config PROTO((const char *tag, const char *dflt));
22void NthElement(DSS_HUGE, DSS_HUGE *);
23
24void dss_random(DSS_HUGE *tgt, DSS_HUGE lower, DSS_HUGE upper, long stream) {
25 *tgt = UnifInt(lower, upper, stream);
26 Seed[stream].usage += 1;
27
28 return;
29}
30
31void row_start(int t) {
32 (void)t;
33 int i;
34 for (i = 0; i <= MAX_STREAM; i++)
35 Seed[i].usage = 0;
36
37 return;
38}
39
40void row_stop_h(int t) {
41 int i;
42
43 /* need to allow for handling the master and detail together */
44 if (t == ORDER_LINE)
45 t = ORDER;
46 if (t == PART_PSUPP)
47 t = PART;
48
49 for (i = 0; i <= MAX_STREAM; i++)
50 if ((Seed[i].table == t) || (Seed[i].table == tdefs[t].child)) {
51 if (set_seeds && (Seed[i].usage > Seed[i].boundary)) {
52 fprintf(stderr, "\nSEED CHANGE: seed[%d].usage = " HUGE_FORMAT "\n", i, Seed[i].usage);
53 Seed[i].boundary = Seed[i].usage;
54 } else {
55 NthElement((Seed[i].boundary - Seed[i].usage), &Seed[i].value);
56#ifdef RNG_TEST
57 Seed[i].nCalls += Seed[i].boundary - Seed[i].usage;
58#endif
59 }
60 }
61 return;
62}
63
64void dump_seeds(int tbl) {
65 int i;
66
67 for (i = 0; i <= MAX_STREAM; i++)
68 if (Seed[i].table == tbl)
69#ifdef RNG_TEST
70 printf("%d(" HUGE_FORMAT "):\t" HUGE_FORMAT "\n", i, Seed[i].nCalls, Seed[i].value);
71#else
72 printf("%d:\t" HUGE_FORMAT "\n", i, Seed[i].value);
73#endif
74 return;
75}
76
77/******************************************************************
78
79 NextRand: Computes next random integer
80
81*******************************************************************/
82
83/*
84 * long NextRand( long nSeed )
85 */
86DSS_HUGE
87NextRand(DSS_HUGE nSeed)
88
89/*
90 * nSeed is the previous random number; the returned value is the
91 * next random number. The routine generates all numbers in the
92 * range 1 .. nM-1.
93 */
94
95{
96 nSeed = (nSeed * 16807) % 2147483647;
97 return (nSeed);
98}
99
100/******************************************************************
101
102 UnifInt: Yields an long uniformly distributed between given bounds
103
104*******************************************************************/
105
106/*
107 * long UnifInt( long nLow, long nHigh, long nStream )
108 */
109DSS_HUGE
110UnifInt(DSS_HUGE nLow, DSS_HUGE nHigh, long nStream)
111
112/*
113 * Returns an integer uniformly distributed between nLow and nHigh,
114 * including * the endpoints. nStream is the random number stream.
115 * Stream 0 is used if nStream is not in the range 0..MAX_STREAM.
116 */
117
118{
119 double dRange;
120 DSS_HUGE nTemp;
121 int32_t nLow32 = (int32_t)nLow, nHigh32 = (int32_t)nHigh;
122
123 if (nStream < 0 || nStream > MAX_STREAM) {
124 nStream = 0;
125 }
126
127 if ((nHigh == MAX_LONG) && (nLow == 0)) {
128 dRange = (double)((DSS_HUGE)(nHigh32 - nLow32) + 1);
129 } else {
130 dRange = (double)(nHigh - nLow + 1);
131 }
132
133 Seed[nStream].value = NextRand(Seed[nStream].value);
134#ifdef RNG_TEST
135 Seed[nStream].nCalls += 1;
136#endif
137 nTemp = (DSS_HUGE)(((double)Seed[nStream].value / dM) * (dRange));
138 return (nLow + nTemp);
139}
140