(root)/
gmp-6.3.0/
tests/
rand/
gen.c
       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  
      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;