1 /* gen.c -- Generate pseudorandom numbers.
2
3 Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library test suite.
6
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
19
20 /* Examples:
21
22 $ gen 10
23 10 integers 0 <= X < 2^32 generated by mpz_urandomb()
24
25 $ gen -f mpf_urandomb 10
26 10 real numbers 0 <= X < 1
27
28 $ gen -z 127 10
29 10 integers 0 <= X < 2^127
30
31 $ gen -f mpf_urandomb -x .9,1 10
32 10 real numbers 0 <= X < .9
33
34 $ gen -s 1 10
35 10 integers, sequence seeded with 1
36
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <limits.h>
43 #include <errno.h>
44 #include <time.h>
45 #include <string.h>
46
47 #if !HAVE_DECL_OPTARG
48 extern char *optarg;
49 extern int optind, opterr;
50 #endif
51
52 #include "gmp-impl.h"
53
main(argc,argv)54 int main (argc, argv)
55 int argc;
56 char *argv[];
57 {
58 const char usage[] =
59 "usage: gen [-bhpq] [-a n] [-c a,c,m2exp] [-C a,c,m] [-f func] [-g alg] [-m n] [-s n] " \
60 "[-x f,t] [-z n] [n]\n" \
61 " n number of random numbers to generate\n" \
62 " -a n ASCII output in radix n (default, with n=10)\n" \
63 " -b binary output\n" \
64 " -c a,c,m2exp use supplied LC scheme\n" \
65 " -f func random function, one of\n" \
66 " mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \
67 " -g alg algorithm, one of mt (default), lc\n" \
68 " -h print this text and exit\n" \
69 " -m n maximum size of generated number plus 1 (0<= X < n) for mpz_urandomm\n" \
70 " -p print used seed on stderr\n" \
71 " -q quiet, no output\n" \
72 " -s n initial seed (default: output from time(3))\n" \
73 " -x f,t exclude all numbers f <= x <= t\n" \
74 " -z n size in bits of generated numbers (0<= X <2^n) (default 32)\n" \
75 "";
76
77 unsigned long int f;
78 unsigned long int n = 0;
79 unsigned long int seed;
80 unsigned long int m2exp = 0;
81 unsigned int size = 32;
82 int seed_from_user = 0;
83 int ascout = 1, binout = 0, printseed = 0;
84 int output_radix = 10;
85 int lc_scheme_from_user = 0;
86 int quiet_flag = 0;
87 mpz_t z_seed;
88 mpz_t z1;
89 mpf_t f1;
90 gmp_randstate_t rstate;
91 int c, i;
92 double drand;
93 long lrand;
94 int do_exclude = 0;
95 mpf_t f_xf, f_xt; /* numbers to exclude from sequence */
96 char *str_xf, *str_xt; /* numbers to exclude from sequence */
97 char *str_a, *str_adder, *str_m;
98 mpz_t z_a, z_m, z_mmax;
99 unsigned long int ul_adder;
100
101 enum
102 {
103 RFUNC_mpz_urandomb = 0,
104 RFUNC_mpz_urandomm,
105 RFUNC_mpf_urandomb,
106 RFUNC_rand,
107 RFUNC_random,
108 } rfunc = RFUNC_mpz_urandomb;
109 char *rfunc_str[] = { "mpz_urandomb", "mpz_urandomm", "mpf_urandomb",
110 "rand", "random" };
111 enum
112 {
113 RNG_MT = 0,
114 RNG_LC
115 };
116 gmp_randalg_t ralg = RNG_MT;
117 /* Texts for the algorithms. The index of each must match the
118 corresponding algorithm in the enum above. */
119 char *ralg_str[] = { "mt", "lc" };
120
121 mpf_init (f_xf);
122 mpf_init (f_xt);
123 mpf_init (f1);
124 mpz_init (z1);
125 mpz_init (z_seed);
126 mpz_init_set_ui (z_mmax, 0);
127
128
129 while ((c = getopt (argc, argv, "a:bc:f:g:hm:n:pqs:z:x:")) != -1)
130 switch (c)
131 {
132 case 'a':
133 ascout = 1;
134 binout = 0;
135 output_radix = atoi (optarg);
136 break;
137
138 case 'b':
139 ascout = 0;
140 binout = 1;
141 break;
142
143 case 'c': /* User supplied LC scheme: a,c,m2exp */
144 if (NULL == (str_a = strtok (optarg, ","))
145 || NULL == (str_adder = strtok (NULL, ","))
146 || NULL == (str_m = strtok (NULL, ",")))
147 {
148 fprintf (stderr, "gen: bad LC scheme parameters: %s\n", optarg);
149 exit (1);
150 }
151 #ifdef HAVE_STRTOUL
152 ul_adder = strtoul (str_adder, NULL, 0);
153 #elif HAVE_STRTOL
154 ul_adder = (unsigned long int) strtol (str_adder, NULL, 0);
155 #else
156 ul_adder = (unsigned long int) atoi (str_adder);
157 #endif
158
159 if (mpz_init_set_str (z_a, str_a, 0))
160 {
161 fprintf (stderr, "gen: bad LC scheme parameter `a': %s\n", str_a);
162 exit (1);
163 }
164 if (ULONG_MAX == ul_adder)
165 {
166 fprintf (stderr, "gen: bad LC scheme parameter `c': %s\n",
167 str_adder);
168 exit (1);
169 }
170 m2exp = atol (str_m);
171
172 lc_scheme_from_user = 1;
173 break;
174
175
176 case 'f':
177 rfunc = -1;
178 for (f = 0; f < sizeof (rfunc_str) / sizeof (*rfunc_str); f++)
179 if (!strcmp (optarg, rfunc_str[f]))
180 {
181 rfunc = f;
182 break;
183 }
184 if (rfunc == -1)
185 {
186 fputs (usage, stderr);
187 exit (1);
188 }
189 break;
190
191 case 'g': /* algorithm */
192 ralg = -1;
193 for (f = 0; f < sizeof (ralg_str) / sizeof (*ralg_str); f++)
194 if (!strcmp (optarg, ralg_str[f]))
195 {
196 ralg = f;
197 break;
198 }
199 if (ralg == -1)
200 {
201 fputs (usage, stderr);
202 exit (1);
203 }
204 break;
205
206 case 'm': /* max for mpz_urandomm() */
207 if (mpz_set_str (z_mmax, optarg, 0))
208 {
209 fprintf (stderr, "gen: bad max value: %s\n", optarg);
210 exit (1);
211 }
212 break;
213
214 case 'p': /* print seed on stderr */
215 printseed = 1;
216 break;
217
218 case 'q': /* quiet */
219 quiet_flag = 1;
220 break;
221
222 case 's': /* user provided seed */
223 if (mpz_set_str (z_seed, optarg, 0))
224 {
225 fprintf (stderr, "gen: bad seed argument %s\n", optarg);
226 exit (1);
227 }
228 seed_from_user = 1;
229 break;
230
231 case 'z':
232 size = atoi (optarg);
233 if (size < 1)
234 {
235 fprintf (stderr, "gen: bad size argument (-z %u)\n", size);
236 exit (1);
237 }
238 break;
239
240 case 'x': /* Exclude. from,to */
241 str_xf = optarg;
242 str_xt = strchr (optarg, ',');
243 if (NULL == str_xt)
244 {
245 fprintf (stderr, "gen: bad exclusion parameters: %s\n", optarg);
246 exit (1);
247 }
248 *str_xt++ = '\0';
249 do_exclude = 1;
250 break;
251
252 case 'h':
253 case '?':
254 default:
255 fputs (usage, stderr);
256 exit (1);
257 }
258 argc -= optind;
259 argv += optind;
260
261 if (! seed_from_user)
262 mpz_set_ui (z_seed, (unsigned long int) time (NULL));
263 seed = mpz_get_ui (z_seed);
264 if (printseed)
265 {
266 fprintf (stderr, "gen: seed used: ");
267 mpz_out_str (stderr, output_radix, z_seed);
268 fprintf (stderr, "\n");
269 }
270
271 mpf_set_prec (f1, size);
272
273 /* init random state and plant seed */
274 switch (rfunc)
275 {
276 case RFUNC_mpf_urandomb:
277 #if 0
278 /* Don't init a too small generator. */
279 size = PREC (f1) * GMP_LIMB_BITS;
280 /* Fall through. */
281 #endif
282 case RFUNC_mpz_urandomb:
283 case RFUNC_mpz_urandomm:
284 switch (ralg)
285 {
286 case RNG_MT:
287 gmp_randinit_mt (rstate);
288 break;
289
290 case RNG_LC:
291 if (! lc_scheme_from_user)
292 gmp_randinit_lc_2exp_size (rstate, MIN (128, size));
293 else
294 gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp);
295 break;
296
297 default:
298 fprintf (stderr, "gen: unsupported algorithm\n");
299 exit (1);
300 }
301
302 gmp_randseed (rstate, z_seed);
303 break;
304
305 case RFUNC_rand:
306 srand (seed);
307 break;
308
309 case RFUNC_random:
310 #ifdef __FreeBSD__ /* FIXME */
311 if (seed_from_user)
312 srandom (seed);
313 else
314 srandomdev ();
315 #else
316 fprintf (stderr, "gen: unsupported algorithm\n");
317 #endif
318 break;
319
320 default:
321 fprintf (stderr, "gen: random function not implemented\n");
322 exit (1);
323 }
324
325 /* set up excludes */
326 if (do_exclude)
327 switch (rfunc)
328 {
329 case RFUNC_mpf_urandomb:
330
331 if (mpf_set_str (f_xf, str_xf, 10) ||
332 mpf_set_str (f_xt, str_xt, 10))
333 {
334 fprintf (stderr, "gen: bad exclusion-from (\"%s\") " \
335 "or exclusion-to (\"%s\") string. no exclusion done.\n",
336 str_xf, str_xt);
337 do_exclude = 0;
338 }
339 break;
340
341 default:
342 fprintf (stderr, "gen: exclusion not implemented for chosen " \
343 "randomization function. all numbers included in sequence.\n");
344 }
345
346 /* generate and print */
347 if (argc > 0)
348 {
349 #if HAVE_STRTOUL
350 n = strtoul (argv[0], (char **) NULL, 10);
351 #elif HAVE_STRTOL
352 n = (unsigned long int) strtol (argv[0], (char **) NULL, 10);
353 #else
354 n = (unsigned long int) atoi (argv[0]);
355 #endif
356 }
357
358 for (f = 0; n == 0 || f < n; f++)
359 {
360 switch (rfunc)
361 {
362 case RFUNC_mpz_urandomb:
363 mpz_urandomb (z1, rstate, size);
364 if (quiet_flag)
365 break;
366 if (binout)
367 {
368 /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/
369 fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n");
370 exit (1);
371 }
372 else
373 {
374 mpz_out_str (stdout, output_radix, z1);
375 puts ("");
376 }
377 break;
378
379 case RFUNC_mpz_urandomm:
380 mpz_urandomm (z1, rstate, z_mmax);
381 if (quiet_flag)
382 break;
383 if (binout)
384 {
385 /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/
386 fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n");
387 exit (1);
388 }
389 else
390 {
391 mpz_out_str (stdout, output_radix, z1);
392 puts ("");
393 }
394 break;
395
396 case RFUNC_mpf_urandomb:
397 mpf_urandomb (f1, rstate, size);
398 if (do_exclude)
399 if (mpf_cmp (f1, f_xf) >= 0 && mpf_cmp (f1, f_xt) <= 0)
400 break;
401 if (quiet_flag)
402 break;
403 if (binout)
404 {
405 fprintf (stderr, "gen: binary output for floating point numbers "\
406 "not implemented\n");
407 exit (1);
408 }
409 else
410 {
411 mpf_out_str (stdout, output_radix, 0, f1);
412 puts ("");
413 }
414 break;
415
416 case RFUNC_rand:
417 i = rand ();
418 #ifdef FLOAT_OUTPUT
419 if (i)
420 drand = (double) i / (double) RAND_MAX;
421 else
422 drand = 0.0;
423 if (quiet_flag)
424 break;
425 if (binout)
426 fwrite (&drand, sizeof (drand), 1, stdout);
427 else
428 printf ("%e\n", drand);
429 #else
430 if (quiet_flag)
431 break;
432 if (binout)
433 fwrite (&i, sizeof (i), 1, stdout);
434 else
435 printf ("%d\n", i);
436 #endif
437 break;
438
439 case RFUNC_random:
440 lrand = random ();
441 if (lrand)
442 drand = (double) lrand / (double) 0x7fffffff;
443 else
444 drand = 0;
445 if (quiet_flag)
446 break;
447 if (binout)
448 fwrite (&drand, sizeof (drand), 1, stdout);
449 else
450 printf ("%e\n", drand);
451 break;
452
453 default:
454 fprintf (stderr, "gen: random function not implemented\n");
455 exit (1);
456 }
457
458 }
459
460 /* clean up */
461 switch (rfunc)
462 {
463 case RFUNC_mpz_urandomb:
464 case RFUNC_mpf_urandomb:
465 gmp_randclear (rstate);
466 break;
467 default:
468 break;
469 }
470 mpf_clear (f1);
471 mpf_clear (f_xf);
472 mpf_clear (f_xt);
473 mpz_clear (z1);
474 mpz_clear (z_seed);
475
476 return 0;
477 }
478
479 static void *debug_dummyz = mpz_dump;
480 static void *debug_dummyf = mpf_dump;
481