| /* gen.c -- Generate pseudorandom numbers. |
| |
| Copyright 1999, 2000, 2002 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library test suite. |
| |
| The GNU MP Library test suite is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 3 of the License, |
| or (at your option) any later version. |
| |
| The GNU MP Library test suite 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 General |
| Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ |
| |
| /* 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 <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <limits.h> |
| #include <errno.h> |
| #include <time.h> |
| #include <string.h> |
| |
| #if !HAVE_DECL_OPTARG |
| extern char *optarg; |
| extern int optind, opterr; |
| #endif |
| |
| #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" \ |
| " -f func random function, one of\n" \ |
| " mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \ |
| " -g alg algorithm, one of mt (default), lc\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" }; |
| enum |
| { |
| RNG_MT = 0, |
| RNG_LC |
| }; |
| gmp_randalg_t ralg = RNG_MT; |
| /* Texts for the algorithms. The index of each must match the |
| corresponding algorithm in the enum above. */ |
| char *ralg_str[] = { "mt", "lc" }; |
| |
| 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: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 */ |
| 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); |
| } |
| m2exp = atol (str_m); |
| |
| 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) * GMP_LIMB_BITS; |
| /* Fall through. */ |
| #endif |
| case RFUNC_mpz_urandomb: |
| case RFUNC_mpz_urandomm: |
| switch (ralg) |
| { |
| case RNG_MT: |
| gmp_randinit_mt (rstate); |
| break; |
| |
| case RNG_LC: |
| if (! lc_scheme_from_user) |
| gmp_randinit_lc_2exp_size (rstate, MIN (128, size)); |
| else |
| gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp); |
| break; |
| |
| default: |
| 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; |