xref: /netbsd-src/external/lgpl3/gmp/dist/tests/rand/gen.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
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.h"
53 #include "gmp-impl.h"
54 
55 int 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 
480 static void *debug_dummyz = mpz_dump;
481 static void *debug_dummyf = mpf_dump;
482