Merge branch 'master' of github.com:jtsiomb/pcboot
[bootcensus] / src / libc / rand.c
1 /*
2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program 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.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 /* random number generator, based on this description of the algorithm
19  * used by the GNU libc: https://www.mathstat.dal.ca/~selinger/random
20  */
21 #include <stdlib.h>
22 #include <inttypes.h>
23
24 static int init_done;
25 static int32_t rng[34];
26 static int32_t *ptr0, *ptr1;
27
28 int rand(void)
29 {
30         int res;
31
32         if(!init_done) {
33                 srand(1);
34         }
35
36         *ptr1 += *ptr0;
37         res = (uint32_t)*ptr1 >> 1;
38         if(++ptr0 >= rng + 34) ptr0 = rng;
39         if(++ptr1 >= rng + 34) ptr1 = rng;
40
41         return res;
42 }
43
44 void srand(unsigned int seed)
45 {
46         int i;
47
48         init_done = 1;
49         if(seed == 0) seed = 1;
50
51         rng[0] = seed;
52         for(i=1; i<31; i++) {
53                 rng[i] = (16807 * rng[i - 1]) % RAND_MAX;
54                 if(rng[i] < 0) rng[i] += RAND_MAX;
55         }
56         for(i=31; i<34; i++) {
57                 rng[i] = rng[i - 31];
58         }
59         ptr0 = rng + 3;
60         ptr1 = rng + 31;
61
62         for(i=34; i<344; i++) {
63                 rand();
64         }
65 }