commit 3e4e851bfa30869e48cee9e15edc6723bee684f5
Author:     Mattias Andrée <[email protected]>
AuthorDate: Thu Mar 3 23:28:05 2016 +0100
Commit:     Mattias Andrée <[email protected]>
CommitDate: Thu Mar 3 23:28:05 2016 +0100

    Add zrand
    
    Signed-off-by: Mattias Andrée <[email protected]>

diff --git a/src/internals.h b/src/internals.h
index 6d05bc2..ba9bd44 100644
--- 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
new file mode 100644
index 0000000..fa1bdfa
--- /dev/null
+++ 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);
+}

Reply via email to