2 * Copyright 2010-2012 Chris Spiegel.
4 * This file is part of Bocfel.
6 * Bocfel is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version
8 * 2 or 3, as published by the Free Software Foundation.
10 * Bocfel is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Bocfel. If not, see <http://www.gnu.org/licenses/>.
29 /* Mersenne Twister. */
30 static uint32_t mt[624];
31 static uint32_t mt_idx = 0;
33 static void zterp_srand(uint32_t s)
36 for(int i = 1; i < 624; i++)
38 mt[i] = 1812433253UL * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i;
43 static void mt_gen_num(void)
45 for(int i = 0; i < 624; i++)
49 y = mt[i] & 0x80000000UL;
50 y |= (mt[(i + 1) % 624]) & 0x7fffffffUL;
52 mt[i] = mt[(i + 397) % 624] ^ (y >> 1);
54 if(y % 2 == 1) mt[i] ^= 2567483615UL;
58 static uint32_t zterp_rand(void)
62 if(mt_idx == 0) mt_gen_num();
66 y ^= (y << 7) & 2636928640UL;
67 y ^= (y << 15) & 4022730752UL;
70 mt_idx = (mt_idx + 1) % 624;
75 static int rng_interval = 0;
76 static int rng_counter = 0;
78 /* Called with 0, seed the PRNG with either
79 * a) a user-provided seed (via -z) if available, or
80 * b) a seed read from a user-provided file/device (via -Z) if
82 * c) a seed derived from a hash of the constituent bytes of the value
83 * returned by time(NULL)
85 * Called with a value 0 < S < 1000, generate a string of numbers 1, 2,
86 * 3, ..., S, 1, 2, 3, ... S, ... as recommended in the remarks to ยง2.
88 * Called with a value >= 1000, use that value as a normal seed.
90 void seed_random(long value)
94 if(options.random_seed == -1)
96 time_t t = time(NULL);
97 unsigned char *p = (unsigned char *)&t;
100 /* time_t hashing based on code by Lawrence Kirby. */
101 for(size_t i = 0; i < sizeof t; i++) s = s * (UCHAR_MAX + 2U) + p[i];
103 if(options.random_device != NULL)
108 fp = fopen(options.random_device, "r");
111 if(fread(&temp, sizeof temp, 1, fp) == 1) s = temp;
120 zterp_srand(options.random_seed);
125 else if(value < 1000)
128 rng_interval = value;
139 long v = (int16_t)zargs[0];
150 if(rng_interval != 0)
153 if(rng_counter == rng_interval) rng_counter = 0;
160 store(res % zargs[0] + 1);