1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * erand48.c |
4 | * |
5 | * This file supplies pg_erand48() and related functions, which except |
6 | * for the names are just like the POSIX-standard erand48() family. |
7 | * (We don't supply the full set though, only the ones we have found use |
8 | * for in Postgres. In particular, we do *not* implement lcong48(), so |
9 | * that there is no need for the multiplier and addend to be variable.) |
10 | * |
11 | * We used to test for an operating system version rather than |
12 | * unconditionally using our own, but (1) some versions of Cygwin have a |
13 | * buggy erand48() that always returns zero and (2) as of 2011, glibc's |
14 | * erand48() is strangely coded to be almost-but-not-quite thread-safe, |
15 | * which doesn't matter for the backend but is important for pgbench. |
16 | * |
17 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
18 | * |
19 | * Portions Copyright (c) 1993 Martin Birgmeier |
20 | * All rights reserved. |
21 | * |
22 | * You may redistribute unmodified or modified versions of this source |
23 | * code provided that the above copyright notice and this and the |
24 | * following conditions are retained. |
25 | * |
26 | * This software is provided ``as is'', and comes with no warranties |
27 | * of any kind. I shall in no event be liable for anything that happens |
28 | * to anyone/anything when using this software. |
29 | * |
30 | * IDENTIFICATION |
31 | * src/port/erand48.c |
32 | * |
33 | *------------------------------------------------------------------------- |
34 | */ |
35 | |
36 | #include "c.h" |
37 | |
38 | #include <math.h> |
39 | |
40 | /* These values are specified by POSIX */ |
41 | #define RAND48_MULT UINT64CONST(0x0005deece66d) |
42 | #define RAND48_ADD UINT64CONST(0x000b) |
43 | |
44 | /* POSIX specifies 0x330e's use in srand48, but the other bits are arbitrary */ |
45 | #define RAND48_SEED_0 (0x330e) |
46 | #define RAND48_SEED_1 (0xabcd) |
47 | #define RAND48_SEED_2 (0x1234) |
48 | |
49 | static unsigned short _rand48_seed[3] = { |
50 | RAND48_SEED_0, |
51 | RAND48_SEED_1, |
52 | RAND48_SEED_2 |
53 | }; |
54 | |
55 | |
56 | /* |
57 | * Advance the 48-bit value stored in xseed[] to the next "random" number. |
58 | * |
59 | * Also returns the value of that number --- without masking it to 48 bits. |
60 | * If caller uses the result, it must mask off the bits it wants. |
61 | */ |
62 | static uint64 |
63 | _dorand48(unsigned short xseed[3]) |
64 | { |
65 | /* |
66 | * We do the arithmetic in uint64; any type wider than 48 bits would work. |
67 | */ |
68 | uint64 in; |
69 | uint64 out; |
70 | |
71 | in = (uint64) xseed[2] << 32 | (uint64) xseed[1] << 16 | (uint64) xseed[0]; |
72 | |
73 | out = in * RAND48_MULT + RAND48_ADD; |
74 | |
75 | xseed[0] = out & 0xFFFF; |
76 | xseed[1] = (out >> 16) & 0xFFFF; |
77 | xseed[2] = (out >> 32) & 0xFFFF; |
78 | |
79 | return out; |
80 | } |
81 | |
82 | |
83 | /* |
84 | * Generate a random floating-point value using caller-supplied state. |
85 | * Values are uniformly distributed over the interval [0.0, 1.0). |
86 | */ |
87 | double |
88 | pg_erand48(unsigned short xseed[3]) |
89 | { |
90 | uint64 x = _dorand48(xseed); |
91 | |
92 | return ldexp((double) (x & UINT64CONST(0xFFFFFFFFFFFF)), -48); |
93 | } |
94 | |
95 | /* |
96 | * Generate a random non-negative integral value using internal state. |
97 | * Values are uniformly distributed over the interval [0, 2^31). |
98 | */ |
99 | long |
100 | pg_lrand48(void) |
101 | { |
102 | uint64 x = _dorand48(_rand48_seed); |
103 | |
104 | return (x >> 17) & UINT64CONST(0x7FFFFFFF); |
105 | } |
106 | |
107 | /* |
108 | * Generate a random signed integral value using caller-supplied state. |
109 | * Values are uniformly distributed over the interval [-2^31, 2^31). |
110 | */ |
111 | long |
112 | pg_jrand48(unsigned short xseed[3]) |
113 | { |
114 | uint64 x = _dorand48(xseed); |
115 | |
116 | return (int32) ((x >> 16) & UINT64CONST(0xFFFFFFFF)); |
117 | } |
118 | |
119 | /* |
120 | * Initialize the internal state using the given seed. |
121 | * |
122 | * Per POSIX, this uses only 32 bits from "seed" even if "long" is wider. |
123 | * Hence, the set of possible seed values is smaller than it could be. |
124 | * Better practice is to use caller-supplied state and initialize it with |
125 | * random bits obtained from a high-quality source of random bits. |
126 | * |
127 | * Note: POSIX specifies a function seed48() that allows all 48 bits |
128 | * of the internal state to be set, but we don't currently support that. |
129 | */ |
130 | void |
131 | pg_srand48(long seed) |
132 | { |
133 | _rand48_seed[0] = RAND48_SEED_0; |
134 | _rand48_seed[1] = (unsigned short) seed; |
135 | _rand48_seed[2] = (unsigned short) (seed >> 16); |
136 | } |
137 | |