1
2 /*
3 * M_APM - mapm_rnd.c
4 *
5 * Copyright (C) 1999 - 2007 Michael C. Ring
6 *
7 * Permission to use, copy, and distribute this software and its
8 * documentation for any purpose with or without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation.
12 *
13 * Permission to modify the software is granted. Permission to distribute
14 * the modified code is granted. Modifications are to be distributed by
15 * using the file 'license.txt' as a template to modify the file header.
16 * 'license.txt' is available in the official MAPM distribution.
17 *
18 * This software is provided "as is" without express or implied warranty.
19 */
20
21 /*
22 *
23 * This file contains the Random Number Generator function.
24 *
25 */
26
27 #include "pgAdmin3.h"
28 #include "pgscript/utilities/mapm-lib/m_apm_lc.h"
29
30 #ifndef _HAVE_NI_LABWIN_CVI_
31 #ifdef MSDOS
32 #include <time.h>
33 #include <sys/timeb.h>
34 #else
35 #include <sys/time.h>
36 extern void M_get_microsec(unsigned long *, long *);
37 #endif
38 #endif
39
40 #ifdef _HAVE_NI_LABWIN_CVI_
41 #include <time.h>
42 #include <utility.h>
43 #include <ansi/math.h>
44 #endif
45
46 extern void M_reverse_string(char *);
47 extern void M_get_rnd_seed(M_APM);
48
49 static M_APM M_rnd_aa;
50 static M_APM M_rnd_mm;
51 static M_APM M_rnd_XX;
52 static M_APM M_rtmp0;
53 static M_APM M_rtmp1;
54
55 static int M_firsttime2 = TRUE;
56
57 /*
58 Used Knuth's The Art of Computer Programming, Volume 2 as
59 the basis. Assuming the random number is X, compute
60 (where all the math is performed on integers) :
61
62 X = (a * X + c) MOD m
63
64 From Knuth:
65
66 'm' should be large, at least 2^30 : we use 1.0E+15
67
68 'a' should be between .01m and .99m and not have a simple
69 pattern. 'a' should not have any large factors in common
70 with 'm' and (since 'm' is a power of 10) if 'a' MOD 200
71 = 21 then all 'm' different possible values will be
72 generated before 'X' starts to repeat.
73
74 We use 'a' = 716805947629621.
75
76 This is a prime number and also meets 'a' MOD 200 = 21.
77 Commented out below are many potential multipliers that
78 are all prime and meet 'a' MOD 200 = 21.
79
80 There are few restrictions on 'c' except 'c' can have no
81 factor in common with 'm', hence we set 'c' = 'a'.
82
83 On the first call, the system time is used to initialize X.
84 */
85
86 /*
87 * the following constants are all potential multipliers. they are
88 * all prime numbers that also meet the criteria of NUM mod 200 = 21.
89 */
90
91 /*
92 439682071525421 439682071528421 439682071529221 439682071529821
93 439682071530421 439682071532021 439682071538821 439682071539421
94 439682071540021 439682071547021 439682071551221 439682071553821
95 439682071555421 439682071557221 439682071558021 439682071558621
96 439682071559821 439652381461621 439652381465221 439652381465621
97 439652381466421 439652381467421 439652381468621 439652381470021
98 439652381471221 439652381477021 439652381484221 439652381488421
99 439652381491021 439652381492021 439652381494021 439652381496821
100 617294387035621 617294387038621 617294387039221 617294387044421
101 617294387045221 617294387048621 617294387051621 617294387051821
102 617294387053621 617294387058421 617294387064221 617294387065621
103 617294387068621 617294387069221 617294387069821 617294387070421
104 617294387072021 617294387072621 617294387073821 617294387076821
105 649378126517621 649378126517821 649378126518221 649378126520821
106 649378126523821 649378126525621 649378126526621 649378126528421
107 649378126529621 649378126530821 649378126532221 649378126533221
108 649378126535221 649378126539421 649378126543621 649378126546021
109 649378126546421 649378126549421 649378126550821 649378126555021
110 649378126557421 649378126560221 649378126561621 649378126562021
111 649378126564621 649378126565821 672091582360421 672091582364221
112 672091582364621 672091582367021 672091582368421 672091582369021
113 672091582370821 672091582371421 672091582376821 672091582380821
114 716805243983221 716805243984821 716805947623621 716805947624621
115 716805947629021 716805947629621 716805947630621 716805947633621
116 716805947634221 716805947635021 716805947635621 716805947642221
117 */
118
119 /****************************************************************************/
M_free_all_rnd()120 void M_free_all_rnd()
121 {
122 if (M_firsttime2 == FALSE)
123 {
124 m_apm_free(M_rnd_aa);
125 m_apm_free(M_rnd_mm);
126 m_apm_free(M_rnd_XX);
127 m_apm_free(M_rtmp0);
128 m_apm_free(M_rtmp1);
129
130 M_firsttime2 = TRUE;
131 }
132 }
133 /****************************************************************************/
m_apm_set_random_seed(char * ss)134 void m_apm_set_random_seed(char *ss)
135 {
136 M_APM btmp;
137
138 if (M_firsttime2)
139 {
140 btmp = M_get_stack_var();
141 m_apm_get_random(btmp);
142 M_restore_stack(1);
143 }
144
145 m_apm_set_string(M_rnd_XX, ss);
146 }
147 /****************************************************************************/
148 /*
149 * compute X = (a * X + c) MOD m where c = a
150 */
m_apm_get_random(M_APM mrnd)151 void m_apm_get_random(M_APM mrnd)
152 {
153
154 if (M_firsttime2) /* use the system time as the initial seed value */
155 {
156 M_firsttime2 = FALSE;
157
158 M_rnd_aa = m_apm_init();
159 M_rnd_XX = m_apm_init();
160 M_rnd_mm = m_apm_init();
161 M_rtmp0 = m_apm_init();
162 M_rtmp1 = m_apm_init();
163
164 /* set the multiplier M_rnd_aa and M_rnd_mm */
165
166 m_apm_set_string(M_rnd_aa, "716805947629621");
167 m_apm_set_string(M_rnd_mm, "1.0E15");
168
169 M_get_rnd_seed(M_rnd_XX);
170 }
171
172 m_apm_multiply(M_rtmp0, M_rnd_XX, M_rnd_aa);
173 m_apm_add(M_rtmp1, M_rtmp0, M_rnd_aa);
174 m_apm_integer_div_rem(M_rtmp0, M_rnd_XX, M_rtmp1, M_rnd_mm);
175 m_apm_copy(mrnd, M_rnd_XX);
176 mrnd->m_apm_exponent -= 15;
177 }
178 /****************************************************************************/
M_reverse_string(char * s)179 void M_reverse_string(char *s)
180 {
181 int ct;
182 char ch, *p1, *p2;
183
184 if ((ct = strlen(s)) <= 1)
185 return;
186
187 p1 = s;
188 p2 = s + ct - 1;
189 ct /= 2;
190
191 while (TRUE)
192 {
193 ch = *p1;
194 *p1++ = *p2;
195 *p2-- = ch;
196
197 if (--ct == 0)
198 break;
199 }
200 }
201 /****************************************************************************/
202
203 #ifndef _HAVE_NI_LABWIN_CVI_
204
205 #ifdef MSDOS
206
207 /****************************************************************************/
208 /*
209 * for DOS / Win 9x/NT systems : use 'ftime'
210 */
M_get_rnd_seed(M_APM mm)211 void M_get_rnd_seed(M_APM mm)
212 {
213 int millisec;
214 time_t timestamp;
215 unsigned long ul;
216 char ss[32], buf1[48], buf2[32];
217 struct timeb timebuffer;
218 M_APM atmp;
219
220 atmp = M_get_stack_var();
221
222 ftime(&timebuffer);
223
224 millisec = (int)timebuffer.millitm;
225 timestamp = timebuffer.time;
226 ul = (unsigned long)(timestamp / 7);
227 ul += timestamp + 537;
228 strcpy(ss, ctime(×tamp)); /* convert to string and copy to ss */
229
230 sprintf(buf1, "%d", (millisec / 10));
231 sprintf(buf2, "%lu", ul);
232
233 ss[0] = ss[18];
234 ss[1] = ss[17];
235 ss[2] = ss[15];
236 ss[3] = ss[14];
237 ss[4] = ss[12];
238 ss[5] = ss[11];
239 ss[6] = ss[9];
240 ss[7] = ss[23];
241 ss[8] = ss[20];
242 ss[9] = '\0';
243
244 M_reverse_string(buf2);
245 strcat(buf1, buf2);
246 strcat(buf1, ss);
247
248 m_apm_set_string(atmp, buf1);
249 atmp->m_apm_exponent = 15;
250 m_apm_integer_divide(mm, atmp, MM_One);
251
252 M_restore_stack(1);
253 }
254 /****************************************************************************/
255
256 #else
257
258 /****************************************************************************/
259 /*
260 * for unix systems : use 'gettimeofday'
261 */
M_get_rnd_seed(M_APM mm)262 void M_get_rnd_seed(M_APM mm)
263 {
264 unsigned long sec3;
265 long usec3;
266 char buf1[32], buf2[32];
267 M_APM atmp;
268
269 atmp = M_get_stack_var();
270 M_get_microsec(&sec3, &usec3);
271
272 sprintf(buf1, "%ld", usec3);
273 sprintf(buf2, "%lu", sec3);
274 M_reverse_string(buf2);
275 strcat(buf1, buf2);
276
277 m_apm_set_string(atmp, buf1);
278 atmp->m_apm_exponent = 15;
279 m_apm_integer_divide(mm, atmp, MM_One);
280
281 M_restore_stack(1);
282 }
283 /****************************************************************************/
M_get_microsec(unsigned long * sec,long * usec)284 void M_get_microsec(unsigned long *sec, long *usec)
285 {
286 struct timeval time_now; /* current time for elapsed time check */
287 struct timezone time_zone; /* time zone for gettimeofday call */
288
289 gettimeofday(&time_now, &time_zone); /* get current time */
290
291 *sec = time_now.tv_sec;
292 *usec = time_now.tv_usec;
293 }
294 /****************************************************************************/
295
296 #endif
297 #endif
298
299 #ifdef _HAVE_NI_LABWIN_CVI_
300
301 /****************************************************************************/
302 /*
303 * for National Instruments LabWindows CVI
304 */
305
M_get_rnd_seed(M_APM mm)306 void M_get_rnd_seed(M_APM mm)
307 {
308 double timer0;
309 int millisec;
310 char *cvi_time, *cvi_date, buf1[64], buf2[32];
311 M_APM atmp;
312
313 atmp = M_get_stack_var();
314
315 cvi_date = DateStr();
316 cvi_time = TimeStr();
317 timer0 = Timer();
318
319 /*
320 * note that Timer() is not syncronized to TimeStr(),
321 * but we don't care here since we are just looking
322 * for a random source of digits.
323 */
324
325 millisec = (int)(0.01 + 1000.0 * (timer0 - floor(timer0)));
326
327 sprintf(buf1, "%d", millisec);
328
329 buf2[0] = cvi_time[6]; /* time format: "HH:MM:SS" */
330 buf2[1] = cvi_time[7];
331 buf2[2] = cvi_time[3];
332 buf2[3] = cvi_time[4];
333 buf2[4] = cvi_time[0];
334 buf2[5] = cvi_time[1];
335
336 buf2[6] = cvi_date[3]; /* date format: "MM-DD-YYYY" */
337 buf2[7] = cvi_date[4];
338 buf2[8] = cvi_date[0];
339 buf2[9] = cvi_date[1];
340 buf2[10] = cvi_date[8];
341 buf2[11] = cvi_date[9];
342 buf2[12] = cvi_date[7];
343
344 buf2[13] = '4';
345 buf2[14] = '7';
346 buf2[15] = '\0';
347
348 strcat(buf1, buf2);
349
350 m_apm_set_string(atmp, buf1);
351 atmp->m_apm_exponent = 15;
352 m_apm_integer_divide(mm, atmp, MM_One);
353
354 M_restore_stack(1);
355 }
356
357 #endif
358
359 /****************************************************************************/
360
361