summaryrefslogtreecommitdiff
path: root/lib/randint.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/randint.c')
-rw-r--r--lib/randint.c227
1 files changed, 0 insertions, 227 deletions
diff --git a/lib/randint.c b/lib/randint.c
deleted file mode 100644
index 53e8c3269..000000000
--- a/lib/randint.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/* Generate random integers.
-
- Copyright (C) 2006 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 <http://www.gnu.org/licenses/>. */
-
-/* Written by Paul Eggert. */
-
-#include <config.h>
-
-#include "randint.h"
-
-#include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#if TEST
-# include <inttypes.h>
-# include <stdio.h>
-
-int
-main (int argc, char **argv)
-{
- randint i;
- randint n = strtoumax (argv[1], NULL, 10);
- randint choices = strtoumax (argv[2], NULL, 10);
- char const *name = argv[3];
- struct randint_source *ints = randint_all_new (name, SIZE_MAX);
-
- for (i = 0; i < n; i++)
- printf ("%"PRIuMAX"\n", randint_choose (ints, choices));
-
- return (randint_all_free (ints) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
-}
-#endif
-
-
-#include "xalloc.h"
-
-#ifndef MAX
-# define MAX(a,b) ((a) < (b) ? (b) : (a))
-#endif
-
-/* 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 NULL (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) : NULL);
-}
-
-/* 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;
-}
-
-/* Return X shifted right by CHAR_BIT bits. */
-static inline randint
-shift_right (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;
-
- for (;;)
- {
- 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 shift_right (RANDINT_MAX) < 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)
-{
- memset (s, 0, 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;
-}