4 * Copyright (c) 1997 Ben Harrison, and others
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
11 /* Purpose: a simple random number generator -BEN- */
17 #include "term/z-rand.h"
20 * Angband 2.7.9 introduced a new (optimized) random number generator,
21 * based loosely on the old "random.c" from Berkeley but with some major
22 * optimizations and algorithm changes. See below for more details.
24 * Code by myself (benh@phial.com) and Randy (randy@stat.tamu.edu).
26 * This code provides (1) a "decent" RNG, based on the "BSD-degree-63-RNG"
27 * used in Angband 2.7.8, but rather optimized, and (2) a "simple" RNG,
28 * based on the simple "LCRNG" currently used in Angband, but "corrected"
29 * to give slightly better values. Both of these are available in two
30 * flavors, first, the simple "mod" flavor, which is fast, but slightly
31 * biased at high values, and second, the simple "div" flavor, which is
32 * less fast (and potentially non-terminating) but which is not biased
33 * and is much less subject to low-bit-non-randomness problems.
35 * You can select your favorite flavor by proper definition of the
36 * "randint0()" macro in the "defines.h" file.
38 * Note that, in Angband 2.8.0, the "state" table will be saved in the
39 * savefile, so a special "initialization" phase will be necessary.
41 * Note the use of the "simple" RNG, first you activate it via
42 * "Rand_quick = TRUE" and "Rand_value = seed" and then it is used
43 * automatically used instead of the "complex" RNG, and when you are
44 * done, you de-activate it via "Rand_quick = FALSE" or choose a new
45 * seed via "Rand_value = seed".
48 * RNG algorithm was fully rewritten. Upper comment is OLD.
57 * Current "state" table for the RNG
58 * Only index 0 to 3 are used
60 u32b Rand_state[RAND_DEG] = {
67 static u32b u32b_rotl(const u32b x, int k) { return (x << k) | (x >> (32 - k)); }
70 * Initialize RNG state
72 static void Rand_seed(u32b seed, u32b *state)
76 for (i = 1; i <= 4; ++i) {
77 seed = 1812433253UL * (seed ^ (seed >> 30)) + i;
83 * Xoshiro128** Algorithm
85 static u32b Rand_Xoshiro128starstar(u32b *state)
87 const u32b result = u32b_rotl(state[1] * 5, 7) * 9;
89 const u32b t = state[1] << 9;
98 state[3] = u32b_rotl(state[3], 11);
103 static const u32b Rand_Xorshift_max = 0xFFFFFFFF;
106 * Initialize the RNG using a new seed
108 void Rand_state_set(u32b seed) { Rand_seed(seed, Rand_state); }
110 void Rand_state_init(void)
114 FILE *fp = fopen(RNG_DEVICE, "r");
118 n = fread(Rand_state, sizeof(Rand_state[0]), 4, fp);
119 } while (n != 4 || (Rand_state[0] | Rand_state[1] | Rand_state[2] | Rand_state[3]) == 0);
123 #elif defined(WINDOWS)
125 HCRYPTPROV hProvider;
127 CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, 0);
130 CryptGenRandom(hProvider, sizeof(Rand_state[0]) * 4, (BYTE *)Rand_state);
131 } while ((Rand_state[0] | Rand_state[1] | Rand_state[2] | Rand_state[3]) == 0);
133 CryptReleaseContext(hProvider, 0);
138 u32b seed = (time(NULL));
140 /* Mutate the seed on Unix machines */
141 seed = ((seed >> 3) * (getpid() << 1));
144 Rand_state_set(seed);
150 * Backup the RNG state
152 void Rand_state_backup(u32b *backup_state)
156 for (i = 0; i < 4; ++i) {
157 backup_state[i] = Rand_state[i];
162 * Restore the RNG state
164 void Rand_state_restore(u32b *backup_state)
168 for (i = 0; i < 4; ++i) {
169 Rand_state[i] = backup_state[i];
174 * Extract a "random" number from 0 to m-1, via "division"
176 static s32b Rand_div_impl(s32b m, u32b *state)
182 /* Hack -- simple case */
186 scaling = Rand_Xorshift_max / m;
190 ret = Rand_Xoshiro128starstar(state);
191 } while (ret >= past);
193 return ret / scaling;
196 s32b Rand_div(s32b m) { return Rand_div_impl(m, Rand_state); }
199 * The number of entries in the "randnor_table"
201 #define RANDNOR_NUM 256
204 * The standard deviation of the "randnor_table"
206 #define RANDNOR_STD 64
209 * The normal distribution table for the "randnor()" function (below)
211 static s16b randnor_table[RANDNOR_NUM] =
213 206, 613, 1022, 1430, 1838, 2245, 2652, 3058,
214 3463, 3867, 4271, 4673, 5075, 5475, 5874, 6271,
215 6667, 7061, 7454, 7845, 8234, 8621, 9006, 9389,
216 9770, 10148, 10524, 10898, 11269, 11638, 12004, 12367,
217 12727, 13085, 13440, 13792, 14140, 14486, 14828, 15168,
218 15504, 15836, 16166, 16492, 16814, 17133, 17449, 17761,
219 18069, 18374, 18675, 18972, 19266, 19556, 19842, 20124,
220 20403, 20678, 20949, 21216, 21479, 21738, 21994, 22245,
222 22493, 22737, 22977, 23213, 23446, 23674, 23899, 24120,
223 24336, 24550, 24759, 24965, 25166, 25365, 25559, 25750,
224 25937, 26120, 26300, 26476, 26649, 26818, 26983, 27146,
225 27304, 27460, 27612, 27760, 27906, 28048, 28187, 28323,
226 28455, 28585, 28711, 28835, 28955, 29073, 29188, 29299,
227 29409, 29515, 29619, 29720, 29818, 29914, 30007, 30098,
228 30186, 30272, 30356, 30437, 30516, 30593, 30668, 30740,
229 30810, 30879, 30945, 31010, 31072, 31133, 31192, 31249,
231 31304, 31358, 31410, 31460, 31509, 31556, 31601, 31646,
232 31688, 31730, 31770, 31808, 31846, 31882, 31917, 31950,
233 31983, 32014, 32044, 32074, 32102, 32129, 32155, 32180,
234 32205, 32228, 32251, 32273, 32294, 32314, 32333, 32352,
235 32370, 32387, 32404, 32420, 32435, 32450, 32464, 32477,
236 32490, 32503, 32515, 32526, 32537, 32548, 32558, 32568,
237 32577, 32586, 32595, 32603, 32611, 32618, 32625, 32632,
238 32639, 32645, 32651, 32657, 32662, 32667, 32672, 32677,
240 32682, 32686, 32690, 32694, 32698, 32702, 32705, 32708,
241 32711, 32714, 32717, 32720, 32722, 32725, 32727, 32729,
242 32731, 32733, 32735, 32737, 32739, 32740, 32742, 32743,
243 32745, 32746, 32747, 32748, 32749, 32750, 32751, 32752,
244 32753, 32754, 32755, 32756, 32757, 32757, 32758, 32758,
245 32759, 32760, 32760, 32761, 32761, 32761, 32762, 32762,
246 32763, 32763, 32763, 32764, 32764, 32764, 32764, 32765,
247 32765, 32765, 32765, 32766, 32766, 32766, 32766, 32767,
251 * Generate a random integer number of NORMAL distribution
253 * The table above is used to generate a pseudo-normal distribution,
254 * in a manner which is much faster than calling a transcendental
255 * function to calculate a true normal distribution.
257 * Basically, entry 64*N in the table above represents the number of
258 * times out of 32767 that a random variable with normal distribution
259 * will fall within N standard deviations of the mean. That is, about
260 * 68 percent of the time for N=1 and 95 percent of the time for N=2.
262 * The table above contains a "faked" final entry which allows us to
263 * pretend that all values in a normal distribution are strictly less
264 * than four standard deviations away from the mean. This results in
265 * "conservative" distribution of approximately 1/32768 values.
267 * Note that the binary search takes up to 16 quick iterations.
269 s16b randnor(int mean, int stand)
275 s16b high = RANDNOR_NUM;
279 /* Roll for probability */
280 tmp = (s16b)randint0(32768);
284 int mid = (low + high) >> 1;
286 /* Move right if forced */
287 if (randnor_table[mid] < tmp) {
291 /* Move left otherwise */
297 /* Convert the index into an offset */
298 offset = (long)stand * (long)low / RANDNOR_STD;
300 /* One half should be negative */
301 if (randint0(100) < 50)
302 return (mean - offset);
304 /* One half should be positive */
305 return (mean + offset);
309 * Generates damage for "2d6" style dice rolls
311 s16b damroll(DICE_NUMBER num, DICE_SID sides)
314 for (i = 0; i < num; i++)
315 sum += randint1(sides);
320 * Same as above, but always maximal
322 s16b maxroll(DICE_NUMBER num, DICE_SID sides) { return (num * sides); }
325 * Given a numerator and a denominator, supply a properly rounded result,
326 * using the RNG to smooth out remainders. -LM-
328 s32b div_round(s32b n, s32b d)
332 /* Refuse to divide by zero */
340 if ((ABS(n) % ABS(d)) > randint0(ABS(d))) {
341 /* Increase the absolute value */
353 * Extract a "random" number from 0 to m-1, using the RNG.
355 * This function should be used when generating random numbers in
356 * "external" program parts like the main-*.c files. It preserves
357 * the current RNG state to prevent influences on game-play.
359 * Could also use rand() from <stdlib.h> directly.
361 s32b Rand_external(s32b m)
363 static bool initialized = FALSE;
364 static u32b Rand_state_external[4];
367 /* Initialize with new seed */
368 u32b seed = (u32b)time(NULL);
369 Rand_seed(seed, Rand_state_external);
373 return Rand_div_impl(m, Rand_state_external);
376 bool next_bool() { return randint0(2) == 0; }