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 | |
21 | const char *env_config PROTO((const char *tag, const char *dflt)); |
22 | void NthElement(DSS_HUGE, DSS_HUGE *); |
23 | |
24 | void 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 | |
31 | void 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 | |
40 | void 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 | |
64 | void 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 | */ |
86 | DSS_HUGE |
87 | NextRand(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 | */ |
109 | DSS_HUGE |
110 | UnifInt(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 | |