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