| /* Generate random integers. | |
| Copyright (C) 2006-2025 Free Software Foundation, Inc. | |
| This program 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. | |
| This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */ | |
| /* Written by Paul Eggert. */ | |
| int | |
| main (int argc, char **argv) | |
| { | |
| randint i; | |
| randint n = strtoumax (argv[1], nullptr, 10); | |
| randint choices = strtoumax (argv[2], nullptr, 10); | |
| char const *name = argv[3]; | |
| struct randint_source *ints = randint_all_new (name, SIZE_MAX); | |
| for (i = 0; i < n; i++) | |
| printf ("%ju\n", randint_choose (ints, choices)); | |
| return (randint_all_free (ints) == 0 ? EXIT_SUCCESS : EXIT_FAILURE); | |
| } | |
| /* A source of random data for generating random integers. */ | |
| struct randint_source | |
| { | |
| /* The source of random bytes. */ | |
| struct randread_source *source; | |
| /* RANDNUM is a buffered random integer, whose information has not | |
| yet been delivered to the caller. It is uniformly distributed in | |
| the range 0 <= RANDNUM <= RANDMAX. If RANDMAX is zero, then | |
| RANDNUM must be zero (and in some sense it is not really | |
| "random"). */ | |
| randint randnum; | |
| randint randmax; | |
| }; | |
| /* Create a new randint_source from SOURCE. */ | |
| struct randint_source * | |
| randint_new (struct randread_source *source) | |
| { | |
| struct randint_source *s = xmalloc (sizeof *s); | |
| s->source = source; | |
| s->randnum = s->randmax = 0; | |
| return s; | |
| } | |
| /* Create a new randint_source by creating a randread_source from | |
| NAME and ESTIMATED_BYTES. Return nullptr (setting errno) if | |
| unsuccessful. */ | |
| struct randint_source * | |
| randint_all_new (char const *name, size_t bytes_bound) | |
| { | |
| struct randread_source *source = randread_new (name, bytes_bound); | |
| return (source ? randint_new (source) : nullptr); | |
| } | |
| /* Return the random data source of *S. */ | |
| struct randread_source * | |
| randint_get_source (struct randint_source const *s) | |
| { | |
| return s->source; | |
| } | |
| /* HUGE_BYTES is true on hosts hosts where randint and unsigned char | |
| have the same width and where shifting by the word size therefore | |
| has undefined behavior. */ | |
| enum { HUGE_BYTES = RANDINT_MAX == UCHAR_MAX }; | |
| /* Return X shifted left by CHAR_BIT bits. */ | |
| static inline randint shift_left (randint x) | |
| { | |
| return HUGE_BYTES ? 0 : x << CHAR_BIT; | |
| } | |
| /* Consume random data from *S to generate a random number in the range | |
| 0 .. GENMAX. */ | |
| randint | |
| randint_genmax (struct randint_source *s, randint genmax) | |
| { | |
| struct randread_source *source = s->source; | |
| randint randnum = s->randnum; | |
| randint randmax = s->randmax; | |
| randint choices = genmax + 1; | |
| while (1) | |
| { | |
| if (randmax < genmax) | |
| { | |
| /* Calculate how many input bytes will be needed, and read | |
| the bytes. */ | |
| size_t i = 0; | |
| randint rmax = randmax; | |
| unsigned char buf[sizeof randnum]; | |
| do | |
| { | |
| rmax = shift_left (rmax) + UCHAR_MAX; | |
| i++; | |
| } | |
| while (rmax < genmax); | |
| randread (source, buf, i); | |
| /* Increase RANDMAX by appending random bytes to RANDNUM and | |
| UCHAR_MAX to RANDMAX until RANDMAX is no less than | |
| GENMAX. This may lose up to CHAR_BIT bits of information | |
| if (HUGE_BYTES ? 0 : RANDINT_MAX >> CHAR_BIT) < GENMAX, | |
| but it is not worth the programming hassle of saving | |
| these bits since GENMAX is rarely that large in practice. */ | |
| i = 0; | |
| do | |
| { | |
| randnum = shift_left (randnum) + buf[i]; | |
| randmax = shift_left (randmax) + UCHAR_MAX; | |
| i++; | |
| } | |
| while (randmax < genmax); | |
| } | |
| if (randmax == genmax) | |
| { | |
| s->randnum = s->randmax = 0; | |
| return randnum; | |
| } | |
| else | |
| { | |
| /* GENMAX < RANDMAX, so attempt to generate a random number | |
| by taking RANDNUM modulo GENMAX+1. This will choose | |
| fairly so long as RANDNUM falls within an integral | |
| multiple of GENMAX+1; otherwise, LAST_USABLE_CHOICE < RANDNUM, | |
| so discard this attempt and try again. | |
| Since GENMAX cannot be RANDINT_MAX, CHOICES cannot be | |
| zero and there is no need to worry about dividing by | |
| zero. */ | |
| randint excess_choices = randmax - genmax; | |
| randint unusable_choices = excess_choices % choices; | |
| randint last_usable_choice = randmax - unusable_choices; | |
| randint reduced_randnum = randnum % choices; | |
| if (randnum <= last_usable_choice) | |
| { | |
| s->randnum = randnum / choices; | |
| s->randmax = excess_choices / choices; | |
| return reduced_randnum; | |
| } | |
| /* Retry, but retain the randomness from the fact that RANDNUM fell | |
| into the range LAST_USABLE_CHOICE+1 .. RANDMAX. */ | |
| randnum = reduced_randnum; | |
| randmax = unusable_choices - 1; | |
| } | |
| } | |
| } | |
| /* Clear *S so that it no longer contains undelivered random data. */ | |
| void | |
| randint_free (struct randint_source *s) | |
| { | |
| explicit_bzero (s, sizeof *s); | |
| free (s); | |
| } | |
| /* Likewise, but also clear the underlying randread object. Return | |
| 0 if successful, -1 (setting errno) otherwise. */ | |
| int | |
| randint_all_free (struct randint_source *s) | |
| { | |
| int r = randread_free (s->source); | |
| int e = errno; | |
| randint_free (s); | |
| errno = e; | |
| return r; | |
| } | |