Austin Schuh | bb1338c | 2024-06-15 19:31:16 -0700 | [diff] [blame^] | 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; |