Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Rand for Elektra.
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "kdbrand.h"
10 : #include <kdbassert.h>
11 : #include <time.h>
12 :
13 : /**
14 : * @brief Non cryptographic pseudo random number generator
15 : *
16 : * By Ray Gardner
17 : * www8.cs.umu.se/~isak/snippets/rg_rand.c
18 : *
19 : * based on "Random Number Generators: Good Ones Are Hard to Find",
20 : * S.K. Park and K.W. Miller, Communications of the ACM 31:10 (Oct 1988),
21 : * and "Two Fast Implementations of the 'Minimal Standard' Random
22 : * Number Generator", David G. Carta, Comm. ACM 33, 1 (Jan 1990), p. 87-88
23 : *
24 : * linear congruential generator f(z) = 16807 z mod (2 ** 31 - 1)
25 : *
26 : * uses L. Schrage's method to avoid overflow problems
27 : *
28 : * Make sure the initial seed is: 0 < seed < ELEKTRARANDMAX
29 : *
30 : * @param seed a pointer to the seed
31 : *
32 : */
33 204386 : void elektraRand (int32_t * seed)
34 : {
35 204386 : ELEKTRA_ASSERT (seed, "seed is NULL");
36 204386 : ELEKTRA_ASSERT (*seed, "seed is 0");
37 204386 : ELEKTRA_ASSERT (*seed < ELEKTRARANDMAX, "seed is equal or bigger than ELEKTRARANDMAX");
38 : uint32_t lo, hi;
39 204386 : lo = 16807 * (int32_t) (*seed & 0xFFFF);
40 204386 : hi = 16807 * (int32_t) ((uint32_t) *seed >> 16);
41 204386 : lo += (hi & 0x7FFF) << 16;
42 204386 : if (lo > ELEKTRARANDMAX)
43 : {
44 41677 : lo &= ELEKTRARANDMAX;
45 41677 : ++lo;
46 : }
47 204386 : lo += hi >> 15;
48 204386 : if (lo > ELEKTRARANDMAX)
49 : {
50 0 : lo &= ELEKTRARANDMAX;
51 0 : ++lo;
52 : }
53 204386 : *seed = (int32_t) lo;
54 204386 : }
55 :
56 : /**
57 : * @brief Random initial seed generator
58 : *
59 : * Generates a random initial seed for the `elektraRand (...)` function.
60 : * Two invocations in the same second return the same random initial seed, due to
61 : * the usage of `time (0)`.
62 : *
63 : * @retval random initial seed
64 : *
65 : */
66 28 : int32_t elektraRandGetInitSeed (void)
67 : {
68 28 : int32_t initSeed = time (0);
69 : // ELEKTRARANDMAX is limit
70 28 : if (initSeed >= ELEKTRARANDMAX)
71 : {
72 0 : initSeed = initSeed % ELEKTRARANDMAX;
73 : }
74 : // 0 not accepted by elektraRand
75 28 : if (!initSeed)
76 : {
77 0 : initSeed = 1;
78 : }
79 : #ifdef KDBRAND_BENCHMARK
80 0 : initSeed = elektraRandBenchmarkInitSeed;
81 : #endif
82 28 : return initSeed;
83 : }
|