1 package io.jawk.jrt;
2
3 /*-
4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5 * Jawk
6 * ჻჻჻჻჻჻
7 * Copyright (C) 2006 - 2026 MetricsHub
8 * ჻჻჻჻჻჻
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23 */
24
25 /**
26 * Simple pseudo-random number generator compatible with the C library
27 * {@code random()} function.
28 */
29 public class BSDRandom {
30
31 private static final int RAND_DEG = 31;
32 private static final int RAND_SEP = 3;
33 private final int[] state = new int[RAND_DEG];
34 private int fptr;
35 private int rptr;
36 private int seed;
37
38 /**
39 * Creates a new generator with the specified seed.
40 *
41 * @param seed Initial pseudo-random seed
42 */
43 public BSDRandom(int seed) {
44 setSeed(seed);
45 }
46
47 /**
48 * Seed the generator. A seed of {@code 0} is transformed to {@code 1}
49 * as in the original implementation.
50 *
51 * @param newSeed New pseudo-random seed
52 */
53 public final void setSeed(int newSeed) {
54 seed = newSeed;
55 int effectiveSeed = newSeed;
56 if (effectiveSeed == 0) {
57 effectiveSeed = 1;
58 }
59 state[0] = effectiveSeed;
60 for (int i = 1; i < RAND_DEG; i++) {
61 long val = 16807L * state[i - 1] % 2147483647L;
62 state[i] = (int) val;
63 }
64 fptr = RAND_SEP;
65 rptr = 0;
66 for (int i = 0; i < 10 * RAND_DEG; i++) {
67 nextInt();
68 }
69 }
70
71 /**
72 * Returns the seed most recently supplied to {@link #setSeed(int)}.
73 *
74 * @return Current pseudo-random seed
75 */
76 public int getSeed() {
77 return seed;
78 }
79
80 private int nextInt() {
81 int val = state[fptr] + state[rptr];
82 state[fptr] = val;
83 if (++fptr >= RAND_DEG) {
84 fptr = 0;
85 }
86 if (++rptr >= RAND_DEG) {
87 rptr = 0;
88 }
89 return (val >>> 1) & 0x7fffffff;
90 }
91
92 /**
93 * Return the next pseudo-random number in the range {@code [0.0,1.0)}.
94 *
95 * @return Next pseudo-random floating-point value
96 */
97 public double nextDouble() {
98 return ((double) nextInt()) / 2147483647.0;
99 }
100 }