rand_r is thread safe, but also reentrant.
Below is the uint128_t code of pseudo random numbers using the xorshift algorithm.
Additional properties:
- shared return
- non-blocking
- thread safe
- superfast
- sown from two sources of entropy
uintx_types.h:
#ifndef UINTX_TYPES_H_INCLUDED #define UINTX_TYPES_H_INCLUDED #include <inttypes.h> #include <ctype.h> typedef __uint128_t uint128_t; typedef __uint64_t uint64_t; #define UINT128_C(hi, lo) (((uint128_t)(hi) << 64) | (uint128_t)(lo)) #define UINT128_MIN UINT128_C( 0x0000000000000000, 0x0000000000000000 ) #define UINT128_0 UINT128_MIN #define UINT128_MAX (~(UINT128_0) - 1) #endif // UINTX_TYPES_H_INCLUDED
lf.h:
#ifndef LF_H_INCLUDED #define LF_H_INCLUDED #define AAF(ADDR, VAL) __sync_add_and_fetch((ADDR), (VAL)) #endif
rand.h:
#ifndef RAND_H_INCLUDED #define RAND_H_INCLUDED #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <time.h> #include <limits.h> #include <fcntl.h> #include <sys/types.h> #include <unistd.h> #include "lf.h" #include "uintx_types.h" #define URANDOM "/dev/random" void srand_init(void); uint128_t rand_range_128(uint128_t min, uint128_t max); #endif // RAND_H_INCLUDED
rand.c:
#include "rand.h" uint64_t r[2]; uint64_t xorshift64star(int index) { uint64_t x; x = r[index]; x ^= x >> 12; // a x ^= x << 25; // b x ^= x >> 27; // c x = x * UINT64_C(2685821657736338717); return AAF(&r[index], x); } void srand_init(void) { struct timespec ts; size_t nbytes; ssize_t bytes_read; int fd; clock_gettime(CLOCK_REALTIME, &ts); r[0] = (uint64_t)(ts.tv_sec * 1.0e9 + ts.tv_nsec); xorshift64star(0); if ((fd = open(URANDOM, O_RDONLY, S_IRUSR | S_IRGRP | S_IROTH)) == -1) { r[1] = r[0] + 1; xorshift64star(1); } else { nbytes = sizeof(r[1]); bytes_read = read(fd, &r[1], nbytes); if ((bytes_read == 0) || (r[1] == 0ull)) { r[1] = r[0] + 1; xorshift64star(1); } close(fd); } } uint64_t rand_64(void) { return xorshift64star(0); } uint128_t rand_128(void) { uint128_t r; r = xorshift64star(0); r = (r << 64) | xorshift64star(1); return r; } uint128_t rand_range_128(uint128_t min, uint128_t max) { return (rand_128() % (max+1-min))+min; }
test.c:
#define KEYS 1000 int main(int argc, char **argv) { int i; uint128_t key; srand_init(); for(i = 0; i <= KEYS; i++) { key = rand_range_128(UINT128_MIN, UINT128_MAX); printf("%016"PRIx64"%016"PRIx64"\n", (uint64_t)(key >> 64), (uint64_t)key); } return 0; }
Compile with gcc (4.9.2) under Linux.
Dawid szymański
source share