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 test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite.  If not, see https://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-impl.h"
53
54int 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
479static void *debug_dummyz = mpz_dump;
480static void *debug_dummyf = mpf_dump;
481