/* gen.c -- Generate pseudorandom numbers. */ /* Copyright (C) 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Examples: $ gen 10 10 integers 0 <= X < 2^32 generated by mpz_urandomb() $ gen -f mpf_urandomb 10 10 real numbers 0 <= X < 1 $ gen -z 127 10 10 integers 0 <= X < 2^127 $ gen -f mpf_urandomb -x .9,1 10 10 real numbers 0 <= X < .9 $ gen -s 1 10 10 integers, sequence seeded with 1 */ #include #include #include #include #include #include #include #if !HAVE_DECL_OPTARG extern char *optarg; extern int optind, opterr; #endif #include "gmp.h" #include "gmp-impl.h" int main (argc, argv) int argc; char *argv[]; { const char usage[] = "usage: gen [-bhpq] [-a n] [-c a,c,m2exp] [-C a,c,m] [-f func] [-g alg] [-m n] [-s n] " \ "[-x f,t] [-z n] [n]\n" \ " n number of random numbers to generate\n" \ " -a n ASCII output in radix n (default, with n=10)\n" \ " -b binary output\n" \ " -c a,c,m2exp use supplied LC scheme\n" \ " -C a,c,m use supplied LC scheme\n" \ " -f func random function, one of\n" \ " mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \ " -g alg algorithm, one of lc (default), bbs\n" \ " -h print this text and exit\n" \ " -m n maximum size of generated number plus 1 (0<= X < n) for mpz_urandomm\n" \ " -p print used seed on stderr\n" \ " -q quiet, no output\n" \ " -s n initial seed (default: output from time(3))\n" \ " -x f,t exclude all numbers f <= x <= t\n" \ " -z n size in bits of generated numbers (0<= X <2^n) (default 32)\n" \ ""; unsigned long int f; unsigned long int n = 0; unsigned long int seed; unsigned long int m2exp = 0; unsigned int size = 32; int seed_from_user = 0; int ascout = 1, binout = 0, printseed = 0; int output_radix = 10; int lc_scheme_from_user = 0; int quiet_flag = 0; mpz_t z_seed; mpz_t z1; mpf_t f1; gmp_randstate_t rstate; int c, i; double drand; long lrand; int do_exclude = 0; mpf_t f_xf, f_xt; /* numbers to exclude from sequence */ char *str_xf, *str_xt; /* numbers to exclude from sequence */ char *str_a, *str_adder, *str_m; mpz_t z_a, z_m, z_mmax; unsigned long int ul_adder; enum { RFUNC_mpz_urandomb = 0, RFUNC_mpz_urandomm, RFUNC_mpf_urandomb, RFUNC_rand, RFUNC_random, } rfunc = RFUNC_mpz_urandomb; char *rfunc_str[] = { "mpz_urandomb", "mpz_urandomm", "mpf_urandomb", "rand", "random" }; gmp_randalg_t ralg = GMP_RAND_ALG_DEFAULT; char *ralg_str[] = { "lc", "bbs" }; mpf_init (f_xf); mpf_init (f_xt); mpf_init (f1); mpz_init (z1); mpz_init (z_seed); mpz_init_set_ui (z_mmax, 0); while ((c = getopt (argc, argv, "a:bc:C:f:g:hm:n:pqs:z:x:")) != -1) switch (c) { case 'a': ascout = 1; binout = 0; output_radix = atoi (optarg); break; case 'b': ascout = 0; binout = 1; break; case 'c': /* User supplied LC scheme: a,c,m2exp */ case 'C': /* User supplied LC scheme: a,c,m */ if (NULL == (str_a = strtok (optarg, ",")) || NULL == (str_adder = strtok (NULL, ",")) || NULL == (str_m = strtok (NULL, ","))) { fprintf (stderr, "gen: bad LC scheme parameters: %s\n", optarg); exit (1); } #ifdef HAVE_STRTOUL ul_adder = strtoul (str_adder, NULL, 0); #elif HAVE_STRTOL ul_adder = (unsigned long int) strtol (str_adder, NULL, 0); #else ul_adder = (unsigned long int) atoi (str_adder); #endif if (mpz_init_set_str (z_a, str_a, 0)) { fprintf (stderr, "gen: bad LC scheme parameter `a': %s\n", str_a); exit (1); } if (ULONG_MAX == ul_adder) { fprintf (stderr, "gen: bad LC scheme parameter `c': %s\n", str_adder); exit (1); } if (c == 'c') m2exp = atol (str_m); else mpz_init_set_str (z_m, str_m, 0); lc_scheme_from_user = 1; break; case 'f': rfunc = -1; for (f = 0; f < sizeof (rfunc_str) / sizeof (*rfunc_str); f++) if (!strcmp (optarg, rfunc_str[f])) { rfunc = f; break; } if (rfunc == -1) { fputs (usage, stderr); exit (1); } break; case 'g': /* algorithm */ ralg = -1; for (f = 0; f < sizeof (ralg_str) / sizeof (*ralg_str); f++) if (!strcmp (optarg, ralg_str[f])) { ralg = f; break; } if (ralg == -1) { fputs (usage, stderr); exit (1); } break; case 'm': /* max for mpz_urandomm() */ if (mpz_set_str (z_mmax, optarg, 0)) { fprintf (stderr, "gen: bad max value: %s\n", optarg); exit (1); } break; case 'p': /* print seed on stderr */ printseed = 1; break; case 'q': /* quiet */ quiet_flag = 1; break; case 's': /* user provided seed */ if (mpz_set_str (z_seed, optarg, 0)) { fprintf (stderr, "gen: bad seed argument %s\n", optarg); exit (1); } seed_from_user = 1; break; case 'z': size = atoi (optarg); if (size < 1) { fprintf (stderr, "gen: bad size argument (-z %u)\n", size); exit (1); } break; case 'x': /* Exclude. from,to */ str_xf = optarg; str_xt = strchr (optarg, ','); if (NULL == str_xt) { fprintf (stderr, "gen: bad exclusion parameters: %s\n", optarg); exit (1); } *str_xt++ = '\0'; do_exclude = 1; break; case 'h': case '?': default: fputs (usage, stderr); exit (1); } argc -= optind; argv += optind; if (! seed_from_user) mpz_set_ui (z_seed, (unsigned long int) time (NULL)); seed = mpz_get_ui (z_seed); if (printseed) { fprintf (stderr, "gen: seed used: "); mpz_out_str (stderr, output_radix, z_seed); fprintf (stderr, "\n"); } mpf_set_prec (f1, size); /* init random state and plant seed */ switch (rfunc) { case RFUNC_mpf_urandomb: #if 0 /* Don't init a too small generator. */ size = PREC (f1) * BITS_PER_MP_LIMB; /* Fall through. */ #endif case RFUNC_mpz_urandomb: case RFUNC_mpz_urandomm: if (! lc_scheme_from_user) { gmp_randinit (rstate, ralg, MIN (128, size)); } else { if (m2exp != 0) gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp); else gmp_randinit_lc (rstate, z_a, ul_adder, z_m); } if (gmp_errno != GMP_ERROR_NONE) { if (gmp_errno & GMP_ERROR_INVALID_ARGUMENT) fprintf (stderr, "gen: asking for too big random state\n"); if (gmp_errno & GMP_ERROR_UNSUPPORTED_ARGUMENT) fprintf (stderr, "gen: unsupported algorithm\n"); exit (1); } gmp_randseed (rstate, z_seed); break; case RFUNC_rand: srand (seed); break; case RFUNC_random: #ifdef __FreeBSD__ /* FIXME */ if (seed_from_user) srandom (seed); else srandomdev (); #else fprintf (stderr, "gen: unsupported algorithm\n"); #endif break; default: fprintf (stderr, "gen: random function not implemented\n"); exit (1); } /* set up excludes */ if (do_exclude) switch (rfunc) { case RFUNC_mpf_urandomb: if (mpf_set_str (f_xf, str_xf, 10) || mpf_set_str (f_xt, str_xt, 10)) { fprintf (stderr, "gen: bad exclusion-from (\"%s\") " \ "or exclusion-to (\"%s\") string. no exclusion done.\n", str_xf, str_xt); do_exclude = 0; } break; default: fprintf (stderr, "gen: exclusion not implemented for chosen " \ "randomization function. all numbers included in sequence.\n"); } /* generate and print */ if (argc > 0) { #if HAVE_STRTOUL n = strtoul (argv[0], (char **) NULL, 10); #elif HAVE_STRTOL n = (unsigned long int) strtol (argv[0], (char **) NULL, 10); #else n = (unsigned long int) atoi (argv[0]); #endif } for (f = 0; n == 0 || f < n; f++) { switch (rfunc) { case RFUNC_mpz_urandomb: mpz_urandomb (z1, rstate, size); if (quiet_flag) break; if (binout) { /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/ fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n"); exit (1); } else { mpz_out_str (stdout, output_radix, z1); puts (""); } break; case RFUNC_mpz_urandomm: mpz_urandomm (z1, rstate, z_mmax); if (quiet_flag) break; if (binout) { /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/ fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n"); exit (1); } else { mpz_out_str (stdout, output_radix, z1); puts (""); } break; case RFUNC_mpf_urandomb: mpf_urandomb (f1, rstate, size); if (do_exclude) if (mpf_cmp (f1, f_xf) >= 0 && mpf_cmp (f1, f_xt) <= 0) break; if (quiet_flag) break; if (binout) { fprintf (stderr, "gen: binary output for floating point numbers "\ "not implemented\n"); exit (1); } else { mpf_out_str (stdout, output_radix, 0, f1); puts (""); } break; case RFUNC_rand: i = rand (); #ifdef FLOAT_OUTPUT if (i) drand = (double) i / (double) RAND_MAX; else drand = 0.0; if (quiet_flag) break; if (binout) fwrite (&drand, sizeof (drand), 1, stdout); else printf ("%e\n", drand); #else if (quiet_flag) break; if (binout) fwrite (&i, sizeof (i), 1, stdout); else printf ("%d\n", i); #endif break; case RFUNC_random: lrand = random (); if (lrand) drand = (double) lrand / (double) 0x7fffffff; else drand = 0; if (quiet_flag) break; if (binout) fwrite (&drand, sizeof (drand), 1, stdout); else printf ("%e\n", drand); break; default: fprintf (stderr, "gen: random function not implemented\n"); exit (1); } } /* clean up */ switch (rfunc) { case RFUNC_mpz_urandomb: case RFUNC_mpf_urandomb: gmp_randclear (rstate); break; default: break; } mpf_clear (f1); mpf_clear (f_xf); mpf_clear (f_xt); mpz_clear (z1); mpz_clear (z_seed); return 0; } static void *debug_dummyz = mpz_dump; static void *debug_dummyf = mpf_dump;