| 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 | |