1/* gen.c -- Generate pseudorandom numbers. 2 3Copyright 1999, 2000, 2002 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library. 6 7The GNU MP Library is free software; you can redistribute it and/or modify 8it under the terms of the GNU Lesser General Public License as published by 9the Free Software Foundation; either version 3 of the License, or (at your 10option) any later version. 11 12The GNU MP Library is distributed in the hope that it will be useful, but 13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15License for more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along with the GNU MP Library. If not, see http://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.h" 53#include "gmp-impl.h" 54 55int main (argc, argv) 56 int argc; 57 char *argv[]; 58{ 59 const char usage[] = 60 "usage: gen [-bhpq] [-a n] [-c a,c,m2exp] [-C a,c,m] [-f func] [-g alg] [-m n] [-s n] " \ 61 "[-x f,t] [-z n] [n]\n" \ 62 " n number of random numbers to generate\n" \ 63 " -a n ASCII output in radix n (default, with n=10)\n" \ 64 " -b binary output\n" \ 65 " -c a,c,m2exp use supplied LC scheme\n" \ 66 " -f func random function, one of\n" \ 67 " mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \ 68 " -g alg algorithm, one of mt (default), lc\n" \ 69 " -h print this text and exit\n" \ 70 " -m n maximum size of generated number plus 1 (0<= X < n) for mpz_urandomm\n" \ 71 " -p print used seed on stderr\n" \ 72 " -q quiet, no output\n" \ 73 " -s n initial seed (default: output from time(3))\n" \ 74 " -x f,t exclude all numbers f <= x <= t\n" \ 75 " -z n size in bits of generated numbers (0<= X <2^n) (default 32)\n" \ 76 ""; 77 78 unsigned long int f; 79 unsigned long int n = 0; 80 unsigned long int seed; 81 unsigned long int m2exp = 0; 82 unsigned int size = 32; 83 int seed_from_user = 0; 84 int ascout = 1, binout = 0, printseed = 0; 85 int output_radix = 10; 86 int lc_scheme_from_user = 0; 87 int quiet_flag = 0; 88 mpz_t z_seed; 89 mpz_t z1; 90 mpf_t f1; 91 gmp_randstate_t rstate; 92 int c, i; 93 double drand; 94 long lrand; 95 int do_exclude = 0; 96 mpf_t f_xf, f_xt; /* numbers to exclude from sequence */ 97 char *str_xf, *str_xt; /* numbers to exclude from sequence */ 98 char *str_a, *str_adder, *str_m; 99 mpz_t z_a, z_m, z_mmax; 100 unsigned long int ul_adder; 101 102 enum 103 { 104 RFUNC_mpz_urandomb = 0, 105 RFUNC_mpz_urandomm, 106 RFUNC_mpf_urandomb, 107 RFUNC_rand, 108 RFUNC_random, 109 } rfunc = RFUNC_mpz_urandomb; 110 char *rfunc_str[] = { "mpz_urandomb", "mpz_urandomm", "mpf_urandomb", 111 "rand", "random" }; 112 enum 113 { 114 RNG_MT = 0, 115 RNG_LC 116 }; 117 gmp_randalg_t ralg = RNG_MT; 118 /* Texts for the algorithms. The index of each must match the 119 corresponding algorithm in the enum above. */ 120 char *ralg_str[] = { "mt", "lc" }; 121 122 mpf_init (f_xf); 123 mpf_init (f_xt); 124 mpf_init (f1); 125 mpz_init (z1); 126 mpz_init (z_seed); 127 mpz_init_set_ui (z_mmax, 0); 128 129 130 while ((c = getopt (argc, argv, "a:bc:f:g:hm:n:pqs:z:x:")) != -1) 131 switch (c) 132 { 133 case 'a': 134 ascout = 1; 135 binout = 0; 136 output_radix = atoi (optarg); 137 break; 138 139 case 'b': 140 ascout = 0; 141 binout = 1; 142 break; 143 144 case 'c': /* User supplied LC scheme: a,c,m2exp */ 145 if (NULL == (str_a = strtok (optarg, ",")) 146 || NULL == (str_adder = strtok (NULL, ",")) 147 || NULL == (str_m = strtok (NULL, ","))) 148 { 149 fprintf (stderr, "gen: bad LC scheme parameters: %s\n", optarg); 150 exit (1); 151 } 152#ifdef HAVE_STRTOUL 153 ul_adder = strtoul (str_adder, NULL, 0); 154#elif HAVE_STRTOL 155 ul_adder = (unsigned long int) strtol (str_adder, NULL, 0); 156#else 157 ul_adder = (unsigned long int) atoi (str_adder); 158#endif 159 160 if (mpz_init_set_str (z_a, str_a, 0)) 161 { 162 fprintf (stderr, "gen: bad LC scheme parameter `a': %s\n", str_a); 163 exit (1); 164 } 165 if (ULONG_MAX == ul_adder) 166 { 167 fprintf (stderr, "gen: bad LC scheme parameter `c': %s\n", 168 str_adder); 169 exit (1); 170 } 171 m2exp = atol (str_m); 172 173 lc_scheme_from_user = 1; 174 break; 175 176 177 case 'f': 178 rfunc = -1; 179 for (f = 0; f < sizeof (rfunc_str) / sizeof (*rfunc_str); f++) 180 if (!strcmp (optarg, rfunc_str[f])) 181 { 182 rfunc = f; 183 break; 184 } 185 if (rfunc == -1) 186 { 187 fputs (usage, stderr); 188 exit (1); 189 } 190 break; 191 192 case 'g': /* algorithm */ 193 ralg = -1; 194 for (f = 0; f < sizeof (ralg_str) / sizeof (*ralg_str); f++) 195 if (!strcmp (optarg, ralg_str[f])) 196 { 197 ralg = f; 198 break; 199 } 200 if (ralg == -1) 201 { 202 fputs (usage, stderr); 203 exit (1); 204 } 205 break; 206 207 case 'm': /* max for mpz_urandomm() */ 208 if (mpz_set_str (z_mmax, optarg, 0)) 209 { 210 fprintf (stderr, "gen: bad max value: %s\n", optarg); 211 exit (1); 212 } 213 break; 214 215 case 'p': /* print seed on stderr */ 216 printseed = 1; 217 break; 218 219 case 'q': /* quiet */ 220 quiet_flag = 1; 221 break; 222 223 case 's': /* user provided seed */ 224 if (mpz_set_str (z_seed, optarg, 0)) 225 { 226 fprintf (stderr, "gen: bad seed argument %s\n", optarg); 227 exit (1); 228 } 229 seed_from_user = 1; 230 break; 231 232 case 'z': 233 size = atoi (optarg); 234 if (size < 1) 235 { 236 fprintf (stderr, "gen: bad size argument (-z %u)\n", size); 237 exit (1); 238 } 239 break; 240 241 case 'x': /* Exclude. from,to */ 242 str_xf = optarg; 243 str_xt = strchr (optarg, ','); 244 if (NULL == str_xt) 245 { 246 fprintf (stderr, "gen: bad exclusion parameters: %s\n", optarg); 247 exit (1); 248 } 249 *str_xt++ = '\0'; 250 do_exclude = 1; 251 break; 252 253 case 'h': 254 case '?': 255 default: 256 fputs (usage, stderr); 257 exit (1); 258 } 259 argc -= optind; 260 argv += optind; 261 262 if (! seed_from_user) 263 mpz_set_ui (z_seed, (unsigned long int) time (NULL)); 264 seed = mpz_get_ui (z_seed); 265 if (printseed) 266 { 267 fprintf (stderr, "gen: seed used: "); 268 mpz_out_str (stderr, output_radix, z_seed); 269 fprintf (stderr, "\n"); 270 } 271 272 mpf_set_prec (f1, size); 273 274 /* init random state and plant seed */ 275 switch (rfunc) 276 { 277 case RFUNC_mpf_urandomb: 278#if 0 279 /* Don't init a too small generator. */ 280 size = PREC (f1) * GMP_LIMB_BITS; 281 /* Fall through. */ 282#endif 283 case RFUNC_mpz_urandomb: 284 case RFUNC_mpz_urandomm: 285 switch (ralg) 286 { 287 case RNG_MT: 288 gmp_randinit_mt (rstate); 289 break; 290 291 case RNG_LC: 292 if (! lc_scheme_from_user) 293 gmp_randinit_lc_2exp_size (rstate, MIN (128, size)); 294 else 295 gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp); 296 break; 297 298 default: 299 fprintf (stderr, "gen: unsupported algorithm\n"); 300 exit (1); 301 } 302 303 gmp_randseed (rstate, z_seed); 304 break; 305 306 case RFUNC_rand: 307 srand (seed); 308 break; 309 310 case RFUNC_random: 311#ifdef __FreeBSD__ /* FIXME */ 312 if (seed_from_user) 313 srandom (seed); 314 else 315 srandomdev (); 316#else 317 fprintf (stderr, "gen: unsupported algorithm\n"); 318#endif 319 break; 320 321 default: 322 fprintf (stderr, "gen: random function not implemented\n"); 323 exit (1); 324 } 325 326 /* set up excludes */ 327 if (do_exclude) 328 switch (rfunc) 329 { 330 case RFUNC_mpf_urandomb: 331 332 if (mpf_set_str (f_xf, str_xf, 10) || 333 mpf_set_str (f_xt, str_xt, 10)) 334 { 335 fprintf (stderr, "gen: bad exclusion-from (\"%s\") " \ 336 "or exclusion-to (\"%s\") string. no exclusion done.\n", 337 str_xf, str_xt); 338 do_exclude = 0; 339 } 340 break; 341 342 default: 343 fprintf (stderr, "gen: exclusion not implemented for chosen " \ 344 "randomization function. all numbers included in sequence.\n"); 345 } 346 347 /* generate and print */ 348 if (argc > 0) 349 { 350#if HAVE_STRTOUL 351 n = strtoul (argv[0], (char **) NULL, 10); 352#elif HAVE_STRTOL 353 n = (unsigned long int) strtol (argv[0], (char **) NULL, 10); 354#else 355 n = (unsigned long int) atoi (argv[0]); 356#endif 357 } 358 359 for (f = 0; n == 0 || f < n; f++) 360 { 361 switch (rfunc) 362 { 363 case RFUNC_mpz_urandomb: 364 mpz_urandomb (z1, rstate, size); 365 if (quiet_flag) 366 break; 367 if (binout) 368 { 369 /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/ 370 fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n"); 371 exit (1); 372 } 373 else 374 { 375 mpz_out_str (stdout, output_radix, z1); 376 puts (""); 377 } 378 break; 379 380 case RFUNC_mpz_urandomm: 381 mpz_urandomm (z1, rstate, z_mmax); 382 if (quiet_flag) 383 break; 384 if (binout) 385 { 386 /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/ 387 fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n"); 388 exit (1); 389 } 390 else 391 { 392 mpz_out_str (stdout, output_radix, z1); 393 puts (""); 394 } 395 break; 396 397 case RFUNC_mpf_urandomb: 398 mpf_urandomb (f1, rstate, size); 399 if (do_exclude) 400 if (mpf_cmp (f1, f_xf) >= 0 && mpf_cmp (f1, f_xt) <= 0) 401 break; 402 if (quiet_flag) 403 break; 404 if (binout) 405 { 406 fprintf (stderr, "gen: binary output for floating point numbers "\ 407 "not implemented\n"); 408 exit (1); 409 } 410 else 411 { 412 mpf_out_str (stdout, output_radix, 0, f1); 413 puts (""); 414 } 415 break; 416 417 case RFUNC_rand: 418 i = rand (); 419#ifdef FLOAT_OUTPUT 420 if (i) 421 drand = (double) i / (double) RAND_MAX; 422 else 423 drand = 0.0; 424 if (quiet_flag) 425 break; 426 if (binout) 427 fwrite (&drand, sizeof (drand), 1, stdout); 428 else 429 printf ("%e\n", drand); 430#else 431 if (quiet_flag) 432 break; 433 if (binout) 434 fwrite (&i, sizeof (i), 1, stdout); 435 else 436 printf ("%d\n", i); 437#endif 438 break; 439 440 case RFUNC_random: 441 lrand = random (); 442 if (lrand) 443 drand = (double) lrand / (double) 0x7fffffff; 444 else 445 drand = 0; 446 if (quiet_flag) 447 break; 448 if (binout) 449 fwrite (&drand, sizeof (drand), 1, stdout); 450 else 451 printf ("%e\n", drand); 452 break; 453 454 default: 455 fprintf (stderr, "gen: random function not implemented\n"); 456 exit (1); 457 } 458 459 } 460 461 /* clean up */ 462 switch (rfunc) 463 { 464 case RFUNC_mpz_urandomb: 465 case RFUNC_mpf_urandomb: 466 gmp_randclear (rstate); 467 break; 468 default: 469 break; 470 } 471 mpf_clear (f1); 472 mpf_clear (f_xf); 473 mpf_clear (f_xt); 474 mpz_clear (z1); 475 mpz_clear (z_seed); 476 477 return 0; 478} 479 480static void *debug_dummyz = mpz_dump; 481static void *debug_dummyf = mpf_dump; 482