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
37 /**
38 * Creates a new generator with the specified seed.
39 *
40 * @param seed Initial pseudo-random seed
41 */
42 public BSDRandom(int seed) {
43 setSeed(seed);
44 }
45
46 /**
47 * Seed the generator. A seed of {@code 0} is transformed to {@code 1}
48 * as in the original implementation.
49 *
50 * @param seed New pseudo-random seed
51 */
52 public final void setSeed(int seed) {
53 if (seed == 0) {
54 seed = 1;
55 }
56 state[0] = seed;
57 for (int i = 1; i < RAND_DEG; i++) {
58 long val = 16807L * state[i - 1] % 2147483647L;
59 state[i] = (int) val;
60 }
61 fptr = RAND_SEP;
62 rptr = 0;
63 for (int i = 0; i < 10 * RAND_DEG; i++) {
64 nextInt();
65 }
66 }
67
68 private int nextInt() {
69 int val = state[fptr] + state[rptr];
70 state[fptr] = val;
71 if (++fptr >= RAND_DEG) {
72 fptr = 0;
73 }
74 if (++rptr >= RAND_DEG) {
75 rptr = 0;
76 }
77 return (val >>> 1) & 0x7fffffff;
78 }
79
80 /**
81 * Return the next pseudo-random number in the range {@code [0.0,1.0)}.
82 *
83 * @return Next pseudo-random floating-point value
84 */
85 public double nextDouble() {
86 return ((double) nextInt()) / 2147483647.0;
87 }
88 }