blob: c8e6c67599b11ca7366b78c528c8bc3f62414320 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* 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;