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