xref: /netbsd-src/external/lgpl3/gmp/dist/tests/rand/gen.c (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
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