| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| |
|
| | #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], 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); |
| | } |
| | #endif |
| |
|
| |
|
| | #include "xalloc.h" |
| |
|
| | |
| | struct randint_source |
| | { |
| | |
| | struct randread_source *source; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | randint randnum; |
| | randint randmax; |
| | }; |
| |
|
| | |
| |
|
| | 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; |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | 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); |
| | } |
| |
|
| | |
| |
|
| | struct randread_source * |
| | randint_get_source (struct randint_source const *s) |
| | { |
| | return s->source; |
| | } |
| |
|
| | |
| | |
| | |
| | enum { HUGE_BYTES = RANDINT_MAX == UCHAR_MAX }; |
| |
|
| | |
| | static inline randint shift_left (randint x) |
| | { |
| | return HUGE_BYTES ? 0 : x << CHAR_BIT; |
| | } |
| |
|
| |
|
| | |
| | |
| |
|
| | 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) |
| | { |
| | |
| | |
| |
|
| | 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); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | 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 |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | 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; |
| | } |
| |
|
| | |
| | |
| | randnum = reduced_randnum; |
| | randmax = unusable_choices - 1; |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | void |
| | randint_free (struct randint_source *s) |
| | { |
| | explicit_bzero (s, sizeof *s); |
| | free (s); |
| | } |
| |
|
| | |
| | |
| |
|
| | int |
| | randint_all_free (struct randint_source *s) |
| | { |
| | int r = randread_free (s->source); |
| | int e = errno; |
| | randint_free (s); |
| | errno = e; |
| | return r; |
| | } |
| |
|