1 /*
2  * Copyright (c) 1996 Otmar Lendl (lendl@cosy.sbg.ac.at)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted without a fee provided that the following
7  * conditions are met:
8  *
9  * 1. This software is only used for private, research, or academic
10  *    purposes.
11  *
12  * 2. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 3. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 4. Any changes made to this package must be submitted to the author.
20  *    The legal status of the submitted changes must allow their inclusion
21  *    into this package under this license.
22  *
23  * 5. Publications in the field of pseudorandom number generation, which
24  *    made use of this package must include a reference to this package.
25  *
26  * Any use of this software in a commercial environment requires a
27  * written licence from the author. Contact Otmar Lendl
28  * (lendl@cosy.sbg.ac.at) to negotiate the terms.
29  *
30  * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
31  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
32  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
33  *
34  * IN NO EVENT SHALL OTMAR LENDL BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
35  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
36  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
37  * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
38  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
39  * OF THIS SOFTWARE.
40  *
41  */
42 /*
43  *
44  *  file.c	PRNG by reading a file (ASCII/BINARY)
45  *
46  *  Author:	Otmar Lendl (lendl@cosy.sbg.ac.at)
47  *
48  *  Last Modification: Fri Nov 15 17:51:39 MET 1996
49  *
50  */
51 
52 /* Modification History:
53 14.11.96: kludge for systems which don't define SEEK_SET
54 13.8.96: First Version.
55 17.10.00: use GNU automake and autoconf
56 01/11/07: replaced prng.free by prng.destroy
57 */
58 
59 #include "prng.h"
60 #include <config.h>
61 
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <math.h>	/* for floor() */
66 
67 #ifndef SEEK_SET
68 #define SEEK_SET 0		/* Sunos seems to need it */
69 #endif
70 
71 /*
72  * prng_file_reset: Reset a File.
73  *
74  * Input:
75  *      gen:  Pointer to a struct prng.
76  *
77  */
prng_file_reset(struct prng * gen)78 void prng_file_reset(struct prng *gen)
79 {
80   fseek(gen->data.file_data.file,0,SEEK_SET);
81 }
82 
83 
84 /*
85  * prng_afile_get_next: Get next number from ASCII File
86  *
87  * Input:
88  *      gen:  Pointer to a struct prng.
89  *
90  */
prng_afile_get_next(struct prng * gen)91 inline double prng_afile_get_next(struct prng *gen)
92 {
93   double d;
94   char line[64];
95 
96   if (fgets(line,63,gen->data.file_data.file) == NULL)
97     {
98       fprintf(stderr,"End of PRN file %s. Starting all over again !\n",
99 	      gen->data.file_data.filename);
100       prng_file_reset(gen);
101 
102       if (fgets(line,63,gen->data.file_data.file) == NULL)
103 	{
104 	  fprintf(stderr,"Serious problems with the file. Giving up.\n");
105 	  exit(1);
106 	}
107     }
108 
109   d = atof(line);
110   return(d - floor(d));		/* make sure number is in range */
111 }
112 
113 /*
114  * prng_afile_get_array: Fill an Array with ASCII File numbers, scaled to [0,1)
115  *
116  * Input:
117  *      gen:	Pointer to a struct prng.
118  *
119  *	array:	Where to put the numbers. ( double *array)
120  *	n:	Size of the array
121  *
122  */
prng_afile_get_array(struct prng * gen,double * array,int n)123 void prng_afile_get_array(struct prng *gen,double *array,int n)
124 {
125   int i;
126 
127   for(i=0;i<n;array[i++] = prng_afile_get_next(gen));
128 }
129 
130 
131 /*
132  * prng_bfile_get_next: Get next number from BINARY File
133  *
134  * Input:
135  *      gen:  Pointer to a struct prng.
136  *
137  */
prng_bfile_get_next(struct prng * gen)138 inline double prng_bfile_get_next(struct prng *gen)
139 {
140   prng_num n;
141 
142   if (fread((void *)&n,sizeof(n),1,gen->data.file_data.file) != 1)
143     {
144       fprintf(stderr,"End of PRN file %s. Starting all over again !\n",
145 	      gen->data.file_data.filename);
146       prng_file_reset(gen);
147 
148       if (fread((void *)&n,sizeof(n),1,gen->data.file_data.file) != 1)
149 	{
150 	  fprintf(stderr,"Serious problems with the file. Giving up.\n");
151 	  exit(1);
152 	}
153     }
154 
155   return( (double) n / (double) (PRNG_NUM_MAX));
156 }
157 
158 
159 /*
160  * prng_bfile_get_array: Fill an Array with BINARY File numbers
161  *
162  * Input:
163  *      gen:	Pointer to a struct prng.
164  *
165  *	array:	Where to put the numbers. ( double *array)
166  *	n:	Size of the array
167  *
168  */
prng_bfile_get_array(struct prng * gen,double * array,int n)169 void prng_bfile_get_array(struct prng *gen,double *array,int n)
170 {
171   int i;
172 
173   for(i=0;i<n;array[i++] = prng_bfile_get_next(gen));
174 }
175 
176 
177 /*
178  * prng_file_free: Free a File.
179  *
180  * Input:
181  *      gen:  Pointer to a struct prng.
182  *
183  */
prng_file_free(struct prng * gen)184 void prng_file_free(struct prng *gen)
185 {
186   fclose(gen->data.file_data.file);
187   prng_generic_free(gen);
188 }
189 
190 
191 /*
192  * Initialize ASCII File generator.
193  *
194  * Input:
195  *	def:	Pointer to struct prng_definition, as returned by
196  *		prng_split_def.
197  *
198  * Returncode:
199  *
200  *	struct prng * on success, NULL else
201  */
prng_afile_init(struct prng_definition * def)202 struct prng *prng_afile_init(struct prng_definition *def)
203 {
204   struct prng_file *g;
205   struct prng *gen;
206 
207   if (strcasecmp("afile",def->type) != 0 )  /* hmm. type seems to be wrong. */
208     {
209       return(NULL);
210     }
211 
212   if (def->num_parameters != 1) 		/* right number of parameters */
213     {
214       return(NULL);
215     }
216 
217   gen = prng_allocate();
218 /*************************** Now prepare the generator itself */
219 
220   g = &(gen->data.file_data);
221 
222   strncpy(g->filename,def->parameter[0],PRNG_MAX_FILE_LEN-1);
223   g->file = fopen(g->filename,"r");
224 
225   if(g->file == NULL)		/* problems with the file ? */
226     {
227       perror("prng_afile_init");
228       free(gen);
229       return(NULL);
230     }
231 
232 /*************************** fill in the generic struct. */
233 
234   gen->reset = prng_file_reset;
235   gen->get_next = prng_afile_get_next;
236   gen->get_array = prng_afile_get_array;
237   gen->destroy = prng_file_free;
238 
239   gen->is_congruential = FALSE;
240   gen->get_next_int = (prng_num (*)(struct prng *)) prng_undefined;
241   gen->modulus = 0;
242 
243   gen->can_seed = FALSE;
244   gen->seed = (void (*)(struct prng *,prng_num seed)) prng_undefined;
245 
246   gen->can_fast_sub = FALSE;
247   gen->get_sub_def = (char *(*)(struct prng *,prng_num s, prng_num i))
248                                         prng_undefined;
249   gen->can_fast_con = FALSE;
250   gen->get_con_def = (char *(*)(struct prng *,prng_num l, prng_num i))
251                                         prng_undefined;
252 
253   gen->long_name = (char *) malloc(strlen(g->filename + 10));
254   if (gen->long_name != NULL)
255     {
256       strcpy(gen->long_name,"afile(");
257       strcat(gen->long_name,g->filename);
258       strcat(gen->long_name,")");
259     }
260 
261   return(gen);
262 }
263 
264 
265 /*
266  * Initialize BINARY File generator.
267  *
268  * Input:
269  *	def:	Pointer to struct prng_definition, as returned by
270  *		prng_split_def.
271  *
272  * Returncode:
273  *
274  *	struct prng * on success, NULL else
275  */
prng_bfile_init(struct prng_definition * def)276 struct prng *prng_bfile_init(struct prng_definition *def)
277 {
278   struct prng_file *g;
279   struct prng *gen;
280 
281   if (strcasecmp("bfile",def->type) != 0 )  /* hmm. type seems to be wrong. */
282     {
283       return(NULL);
284     }
285 
286   if (def->num_parameters != 1) 		/* right number of parameters */
287     {
288       return(NULL);
289     }
290 
291   gen = prng_allocate();
292 /*************************** Now prepare the generator itself */
293 
294   g = &(gen->data.file_data);
295 
296   strncpy(g->filename,def->parameter[0],PRNG_MAX_FILE_LEN-1);
297   g->file = fopen(g->filename,"r");
298 
299   if(g->file == NULL)		/* problems with the file ? */
300     {
301       perror("prng_bfile_init");
302       free(gen);
303       return(NULL);
304     }
305 
306 /*************************** fill in the generic struct. */
307 
308   gen->reset = prng_file_reset;
309   gen->get_next = prng_bfile_get_next;
310   gen->get_array = prng_bfile_get_array;
311   gen->destroy = prng_file_free;
312 
313   gen->is_congruential = FALSE;
314   gen->get_next_int = (prng_num (*)(struct prng *)) prng_undefined;
315   gen->modulus = 0;
316 
317   gen->can_seed = FALSE;
318   gen->seed = (void (*)(struct prng *,prng_num seed)) prng_undefined;
319 
320   gen->can_fast_sub = FALSE;
321   gen->get_sub_def = (char *(*)(struct prng *,prng_num s, prng_num i))
322                                         prng_undefined;
323   gen->can_fast_con = FALSE;
324   gen->get_con_def = (char *(*)(struct prng *,prng_num l, prng_num i))
325                                         prng_undefined;
326 
327 
328   gen->long_name = (char *) malloc(strlen(g->filename + 10));
329   if (gen->long_name != NULL)
330     {
331       strcpy(gen->long_name,"bfile(");
332       strcat(gen->long_name,g->filename);
333       strcat(gen->long_name,")");
334     }
335 
336   return(gen);
337 }
338 
339