commit 3e4e851bfa30869e48cee9e15edc6723bee684f5
parent d6987458f21cf1890045f2606d0f8ec4d2225b44
Author: Mattias Andrée <maandree@kth.se>
Date: Thu, 3 Mar 2016 23:28:05 +0100
Add zrand
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
2 files changed, 97 insertions(+), 1 deletion(-)
diff --git a/src/internals.h b/src/internals.h
@@ -33,7 +33,8 @@
#define LIST_CONSTS\
X(libzahl_const_1e19, zsetu, 10000000000000000000ULL) /* The largest power of 10 < 2⁶⁴. */\
- X(libzahl_const_1e9, zsetu, 1000000000ULL) /* The largest power of 10 < 2³². */
+ X(libzahl_const_1e9, zsetu, 1000000000ULL) /* The largest power of 10 < 2³². */\
+ X(libzahl_const_1, zsetu, 1)
#define X(x) extern z_t x;
LIST_TEMPS
diff --git a/src/zrand.c b/src/zrand.c
@@ -0,0 +1,95 @@
+/* See LICENSE file for copyright and license details. */
+#include "internals"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifndef FAST_RANDOM_PATHNAME
+# define FAST_RANDOM_PATHNAME "/dev/urandom"
+#endif
+
+#ifndef SECURE_RANDOM_PATHNAME
+# define SECURE_RANDOM_PATHNAME "/dev/random"
+#endif
+
+
+static void
+zrand_get_random_bits(z_t r, size_t bits, int fd)
+{
+ size_t read_total, n, chars = CEILING_BITS_TO_CHARS(bits);
+ ssize_t read_just;
+ uint32_t mask = 1;
+
+ if (r->alloced < chars)
+ zahl_realloc(r, chars);
+
+ for (n = chars << LB_BITS_PER_CHAR; n;) {
+ read_just = read(fd, (char *)(r->chars) + read_total, n);
+ if (read_just < 0)
+ FAILURE_JUMP();
+ read_total += read_just;
+ n -= read_just;
+ }
+
+ bit = BITS_IN_LAST_CHAR(bit)
+ mask <<= bit;
+ mask -= 1;
+
+ r->chars[chars - 1] &= mask;
+ for (n = chars; n--;) {
+ if (r->chars[n]) {
+ r->used = n + 1;
+ SET_SIGNUM(r, 1);
+ return;
+ }
+ }
+ SET_SIGNUM(r, 0);
+}
+
+void
+zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n)
+{
+ const char *pathname = 0;
+ size_t bits;
+ int fd;
+
+ switch (dev) {
+ case FAST_RANDOM:
+ pathname = FAST_RANDOM_PATHNAME;
+ break;
+ case SECURE_RANDOM:
+ pathname = SECURE_RANDOM_PATHNAME;
+ break;
+ default:
+ abort();
+ }
+
+ if (zzero(n)) {
+ SET_SIGNUM(r, 0);
+ return;
+ }
+
+ fd = open(pathname, O_RDONLY);
+
+ switch (dist) {
+ case QUASIUNIFORM:
+ bits = zbits(n);
+ zrand_get_random_bits(r, bits, fd);
+ zadd(r, r, libzahl_const_1);
+ zmul(r, r, n);
+ zrsh(r, r, bits);
+ break;
+
+ case UNIFORM:
+ bits = zbits(n);
+ do
+ zrand_get_random_bits(r, bits, fd);
+ while (zcmp(r, n) > 0);
+ break;
+
+ default:
+ abort();
+ }
+
+ close(fd);
+}