Home
Highly Reusable Software By activity User Interface Text Strings Math Processing
Stored Data
Communications
Hard World File System
|
#License - #Source code - #Example Use -
#include <librock/target/bitypes.h> #include <librock/math.h> uint32_t librock_random(struct librock_random_s *state); struct librock_random_s * librock_srandom( struct librock_random_s *state, /* Pointer to state, or NULL */ uint32_t x, /* Random seed value */ char *prand, /* Random data for state, or NULL */ int n); /* Amount of state information */
This random number generation package is adapted from OpenBSD libc/random.c, (The code is originally from BSD 4.2.) The output and behavior is identical, but the calling conventions were modified to take a pointer to state information as an argument. This efficiently supports multiple concurrent state information blocks within a single process, without the inefficient copying of the original BSD setstate() routine.
Typical use would be to generate pseudo-random streams for games or repeatable tests. See below for typical code.
librock_random() returns a 31-bit random number, in a determined sequence set by the starting seed and initial state. The first argument is a pointer to the state information, which can be NULL to use an internal (static) block with 128 bytes of state, matching the BSD 4.2 output. Otherwise it should be a pointer previously given or returned from a call to librock_srandom().
librock_srandom intializes state information. When the first parameter is NULL, this will malloc() space, and the caller is responsible for calling free(). The number of bytes for static or external allocations of state information is #define'd as librock_SIZEOF_random_s in the header file. Since other pointers and values are kept in the state information block, it is not compatible with the BSD setstate() and initstate() routines.
The parameter n, for the amount of state information is rounded down to the closest or equal value of 1, 32, 64, 128, and 256. (Using 1 is not recommended, even though it is fastest.) The values larger than 1 are equally efficient, but larger values keep more state and have a longer period without repeating.) The return value is NULL on error, or the pointer to the state information block.
prand is an optional pointer to a block of n bytes of random data used to initialize the state. If prand is NULL, the seed value x (or 1 if the seed is 0) is used to initialize the state.
The multi-threaded caller must perform locking when there could be concurrent calls with the same state pointer argument.
The random number generation technique is a linear feedback shift register approach, employing trinomials (since there are fewer terms to sum up that way). In this approach, the least significant bit of all the numbers in the state table will act as a linear feedback shift register, and will have period 2^deg - 1 (where deg is the degree of the polynomial being used, assuming that the polynomial is irreducible and primitive). The higher order bits will have longer periods, since their values are also influenced by pseudo-random carries out of the lower bits. The total period of the generator is approximately deg*(2**deg - 1); thus doubling the amount of state information has a vast influence on the period of the generator. Note: the deg*(2**deg - 1) is an approximation only good for large deg, when the period of the shift register is the dominant factor. With deg equal to seven, the period is actually much longer than the 7*(2**7 - 1) predicted by this formula.
To generate a uniformly distributed pseudo-random integer in the range 0,(N-1) inclusive when N <= 2^31, you could use the following. (If N is unchanging, precalculation of maxuniform will save time.)
#ifdef librock_TYPICAL_USE_random #include <librock/target/bitypes.h> #include <librock/math.h> struct librock_random_s *pstate; int N = 8000; pstate = librock_srandom(0,0x1234,0,0); if (N > 0) { long maxuniform = 0x8000000 - (0x80000000 % N); long r; do { r = librock_random(pstate); } while (r >= maxuniform); r %= N; printf("%ld\n",r); } #endifTo generate a uniformly distributed pseudo-random floating point in the range 0 to N, you could use the following. (If N is unchanging, precalculation of a term will save time.)
#ifdef librock_TYPICAL_USE_2_random printf("%g\n",(double) librock_random(0) * (N / (double) 0x80000000)); #endifThe original BSD 4.2 code included a srandomdev() routine which seeded the generator with random data. Getting good random seed data for security purposes is a hard problem. Picking clocks (even microsecond clocks) would enable attackers to have a small search space.
For reference the OpenBSD srandomdev() code tried to read from /dev/arandom/, and failing that would use the very less strong gettimeofday().
malloc() // librock_srandom if argument is 0 ldiv // librock_srandom memcpy // librock_srandom if prand is not 0
Copyright (c) 1983 Regents of the University of California. License text in <librock/license/bsdorig.txt> librock_LIDESC_HC=526b72abf87ca6429325f0b7b0ae8dab0986c030 Licensed under BSD-ish license, NO WARRANTY. Copies must retain this block. Modifications Copyright (c) 2001 Forrest J. Cavalier III d-b-a Mib Software License text in <librock/license/librock.txt> librock_LIDESC_HC=12440211096131f5976d36be0cddca4cd9152e45
librock_random passed tests in trandom (Unix/Linux/BSD: 2002/08/08 sys=FreeBSD using gcc)
librock_random passed tests in trandom_main (WIN32: 2002/08/08 sys=NT 4.0 using MSVC)
librock_srandom passed tests in trandom (Unix/Linux/BSD: 2002/08/08 sys=FreeBSD using gcc)
librock_srandom passed tests in trandom_main (WIN32: 2002/08/08 sys=NT 4.0 using MSVC)
Verbatim copying and distribution of this generated page is permitted in any medium provided that no changes are made.
(The source of this manual page may be covered by a more permissive license which allows modifications.)
Want to help? We welcome comments, patches. -- Need help? Request paid support.