View Javadoc
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 }