5
* Copyright (C) 1999 - 2007 Michael C. Ring
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.
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.
18
* This software is provided "as is" without express or implied warranty.
23
* This file contains the Random Number Generator function.
28
#include "pgscript/utilities/mapm-lib/m_apm_lc.h"
30
#ifndef _HAVE_NI_LABWIN_CVI_
33
#include <sys/timeb.h>
36
extern void M_get_microsec(unsigned long *, long *);
40
#ifdef _HAVE_NI_LABWIN_CVI_
43
#include <ansi/math.h>
46
extern void M_reverse_string(char *);
47
extern void M_get_rnd_seed(M_APM);
49
static M_APM M_rnd_aa;
50
static M_APM M_rnd_mm;
51
static M_APM M_rnd_XX;
55
static int M_firsttime2 = TRUE;
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) :
66
'm' should be large, at least 2^30 : we use 1.0E+15
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.
74
We use 'a' = 716805947629621.
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.
80
There are few restrictions on 'c' except 'c' can have no
81
factor in common with 'm', hence we set 'c' = 'a'.
83
On the first call, the system time is used to initialize X.
87
* the following constants are all potential multipliers. they are
88
* all prime numbers that also meet the criteria of NUM mod 200 = 21.
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
119
/****************************************************************************/
120
void M_free_all_rnd()
122
if (M_firsttime2 == FALSE)
124
m_apm_free(M_rnd_aa);
125
m_apm_free(M_rnd_mm);
126
m_apm_free(M_rnd_XX);
133
/****************************************************************************/
134
void m_apm_set_random_seed(char *ss)
140
btmp = M_get_stack_var();
141
m_apm_get_random(btmp);
145
m_apm_set_string(M_rnd_XX, ss);
147
/****************************************************************************/
149
* compute X = (a * X + c) MOD m where c = a
151
void m_apm_get_random(M_APM mrnd)
154
if (M_firsttime2) /* use the system time as the initial seed value */
156
M_firsttime2 = FALSE;
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();
164
/* set the multiplier M_rnd_aa and M_rnd_mm */
166
m_apm_set_string(M_rnd_aa, "716805947629621");
167
m_apm_set_string(M_rnd_mm, "1.0E15");
169
M_get_rnd_seed(M_rnd_XX);
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;
178
/****************************************************************************/
179
void M_reverse_string(char *s)
184
if ((ct = strlen(s)) <= 1)
201
/****************************************************************************/
203
#ifndef _HAVE_NI_LABWIN_CVI_
207
/****************************************************************************/
209
* for DOS / Win 9x/NT systems : use 'ftime'
211
void M_get_rnd_seed(M_APM mm)
216
char ss[32], buf1[48], buf2[32];
217
struct timeb timebuffer;
220
atmp = M_get_stack_var();
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 */
230
sprintf(buf1,"%d",(millisec / 10));
231
sprintf(buf2,"%lu",ul);
244
M_reverse_string(buf2);
248
m_apm_set_string(atmp, buf1);
249
atmp->m_apm_exponent = 15;
250
m_apm_integer_divide(mm, atmp, MM_One);
254
/****************************************************************************/
258
/****************************************************************************/
260
* for unix systems : use 'gettimeofday'
262
void M_get_rnd_seed(M_APM mm)
266
char buf1[32], buf2[32];
269
atmp = M_get_stack_var();
270
M_get_microsec(&sec3,&usec3);
272
sprintf(buf1,"%ld",usec3);
273
sprintf(buf2,"%lu",sec3);
274
M_reverse_string(buf2);
277
m_apm_set_string(atmp, buf1);
278
atmp->m_apm_exponent = 15;
279
m_apm_integer_divide(mm, atmp, MM_One);
283
/****************************************************************************/
284
void M_get_microsec(unsigned long *sec, long *usec)
286
struct timeval time_now; /* current time for elapsed time check */
287
struct timezone time_zone; /* time zone for gettimeofday call */
289
gettimeofday(&time_now, &time_zone); /* get current time */
291
*sec = time_now.tv_sec;
292
*usec = time_now.tv_usec;
294
/****************************************************************************/
299
#ifdef _HAVE_NI_LABWIN_CVI_
301
/****************************************************************************/
303
* for National Instruments LabWindows CVI
306
void M_get_rnd_seed(M_APM mm)
310
char *cvi_time, *cvi_date, buf1[64], buf2[32];
313
atmp = M_get_stack_var();
315
cvi_date = DateStr();
316
cvi_time = TimeStr();
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.
325
millisec = (int)(0.01 + 1000.0 * (timer0 - floor(timer0)));
327
sprintf(buf1, "%d", millisec);
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];
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];
350
m_apm_set_string(atmp, buf1);
351
atmp->m_apm_exponent = 15;
352
m_apm_integer_divide(mm, atmp, MM_One);
359
/****************************************************************************/