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(&timestamp));       /* 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