001package squidpony.squidmath; 002 003import squidpony.StringKit; 004 005import java.io.Serializable; 006 007 008/** 009 * A random number generator that is extremely fast but can't return all possible results. ThrustAltRNG passes TestU01's 010 * BigCrush, which is a difficult statistical quality test. On <a href="http://gjrand.sourceforge.net/">gjrand</a>'s 011 * "testunif" checks, this does very well on 100GB of tested data, with the "Overall summary one sided P-value P = 012 * 0.981", where 1 is perfect and 0.1 or less is a failure. On <a href="http://pracrand.sourceforge.net/">PractRand</a>, 013 * this passes all 32TB of generated numbers without finding any failures (and very rarely finding anomalies). Like 014 * {@link LightRNG}, this changes its state with a steady fixed increment, and does hash-like adjustments to the 015 * current state to randomize it (the change is not a cipher because it is not reversible; this may be an advantage 016 * for some usage). The period on ThrustAltRNG is 2 to the 64. ThrustAltRNG is very strong on speed, outpacing the 017 * default generator for {@link RNG}, {@link DiverRNG}, by a small margin, and most other RandomnessSources in 018 * SquidLib by a larger margin (it is slower than {@link MiniMover64RNG}, but this has a better period). Similarly to 019 * other hash-like PRNGs such as {@link LightRNG}, ThrustAltRNG has a {@link #determine(long)} method that takes a state 020 * as a long and returns a deterministic random number (each input has one output, though in this case the reverse isn't 021 * true and some outputs will be returned by multiple inputs). Like LightRNG, but unlike an LCG such as 022 * {@link java.util.Random}, changing the seed even slightly generally produces completely different results, which 023 * applies primarily to determine() but also the first number generated in a series of nextLong() calls. This generator 024 * is GWT-safe but will be much slower on GWT than generators designed for usage there, such as {@link GWTRNG} or 025 * {@link Lathe32RNG}. 026 * <br> 027 * Because this generator can't produce all longs (it is not equidistributed), that alone is enough to discount its use 028 * in some (mainly scientific) scenarios, although it passes all major testing suites (TestU01's BigCrush, PractRand 029 * over the full 32TB of tests, and gjrand to some degree, at least better than most). DiverRNG is the default 030 * generator after ThrustAltRNG was used extensively for some time, since DiverRNG passes the same tests, is almost as 031 * fast, and is known to produce all longs over the course of its period. One small change was required to pass a test 032 * added in PractRand version 0.94, going from a shift of 22 to a shift of 23 at the end of the generation. Without this 033 * change, ThrustAltRNG will eventually fail PractRand (failing "TMFn" tests, which check for patterns like those in a 034 * linear congruential generator such as {@link java.util.Random}), but only after 16TB of data has been analyzed. Even 035 * if using a version before the shift was changed on June 8, 2019, the quality is probably fine. 036 * <br> 037 * There was a ThrustRNG in SquidLib, but it failed statistical tests badly in roughly a minute of testing, so even 038 * though it was faster it probably wasn't a good idea to use it. ThrustAltRNG modifies ThrustRNG's algorithm very 039 * heavily, and isn't especially similar, but the name stuck, I guess. The idea behind the name is that the generator is 040 * acting like a thrust in fencing, pushing quickly but leaving a hole (not in the quality, but in the distribution). 041 * <br> 042 * Created by Tommy Ettinger on 10/18/2017. 043 */ 044public final class ThrustAltRNG implements StatefulRandomness, SkippingRandomness, Serializable { 045 private static final long serialVersionUID = 3L; 046 /** 047 * Can be any long value. 048 */ 049 public long state; 050 051 /** 052 * Creates a new generator seeded using Math.random. 053 */ 054 public ThrustAltRNG() { 055 this((long) ((Math.random() - 0.5) * 0x10000000000000L) 056 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L)); 057 } 058 059 public ThrustAltRNG(final long seed) { 060 state = seed; 061 } 062 063 /** 064 * Get the current internal state of the StatefulRandomness as a long. 065 * 066 * @return the current internal state of this object. 067 */ 068 @Override 069 public long getState() { 070 return state; 071 } 072 073 /** 074 * Set the current internal state of this StatefulRandomness with a long. 075 * 076 * @param state a 64-bit long 077 */ 078 @Override 079 public void setState(long state) { 080 this.state = state; 081 } 082 083 /** 084 * Using this method, any algorithm that might use the built-in Java Random 085 * can interface with this randomness source. 086 * 087 * @param bits the number of bits to be returned 088 * @return the integer containing the appropriate number of bits 089 */ 090 @Override 091 public final int next(final int bits) { 092 final long s = (state += 0x6C8E9CF570932BD5L); 093 final long z = (s ^ (s >>> 25)) * (s | 0xA529L); 094 return (int)(z ^ (z >>> 23)) >>> (32 - bits); 095 } 096 /** 097 * Using this method, any algorithm that needs to efficiently generate more 098 * than 32 bits of random data can interface with this randomness source. 099 * <p> 100 * Get a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive). 101 * 102 * @return a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive) 103 */ 104 @Override 105 public final long nextLong() { 106 final long s = (state += 0x6C8E9CF570932BD5L); 107 final long z = (s ^ (s >>> 25)) * (s | 0xA529L); 108 return z ^ (z >>> 23); 109 } 110 111 /** 112 * Advances or rolls back the ThrustAltRNG's state without actually generating each number. Skips forward 113 * or backward a number of steps specified by advance, where a step is equal to one call to nextLong(), 114 * and returns the random number produced at that step (you can get the state with {@link #getState()}). 115 * 116 * @param advance Number of future generations to skip over; can be negative to backtrack, 0 gets the most-recently-generated number 117 * @return the random long generated after skipping forward or backwards by {@code advance} numbers 118 */ 119 @Override 120 public final long skip(long advance) { 121 final long s = (state += 0x6C8E9CF570932BD5L * advance); 122 final long z = (s ^ (s >>> 25)) * (s | 0xA529L); 123 return z ^ (z >>> 23); 124 } 125 126 127 /** 128 * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the 129 * copy, both will generate the same sequence of random numbers from the point copy() was called. This just need to 130 * copy the state so it isn't shared, usually, and produce a new value with the same exact state. 131 * 132 * @return a copy of this RandomnessSource 133 */ 134 @Override 135 public ThrustAltRNG copy() { 136 return new ThrustAltRNG(state); 137 } 138 @Override 139 public String toString() { 140 return "ThrustAltRNG with state 0x" + StringKit.hex(state) + 'L'; 141 } 142 143 @Override 144 public boolean equals(Object o) { 145 if (this == o) return true; 146 if (o == null || getClass() != o.getClass()) return false; 147 148 ThrustAltRNG thrustAltRNG = (ThrustAltRNG) o; 149 150 return state == thrustAltRNG.state; 151 } 152 153 @Override 154 public int hashCode() { 155 return (int) (state ^ (state >>> 32)); 156 } 157 158 /** 159 * Returns a random permutation of state; if state is the same on two calls to this, this will return the same 160 * number. This is expected to be called with some changing variable, e.g. {@code determine(++state)}, where 161 * the increment for state should be odd but otherwise doesn't really matter. This multiplies state by 162 * {@code 0x6C8E9CF570932BD5L} within this method, so using a small increment won't be much different from using a 163 * very large one, as long as it is odd. The period is 2 to the 64 if you increment or decrement by 1. 164 * @param state a variable that should be different every time you want a different random result; 165 * using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to 166 * generate numbers in reverse order 167 * @return a pseudo-random permutation of state 168 */ 169 public static long determine(long state) { 170 return (state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23); 171 } 172 //for quick one-line pastes of how the algo can be used with "randomize(++state)" 173 //public static long randomize(long state) { return (state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23); } 174 175 /** 176 * Returns a random float that is deterministic based on state; if state is the same on two calls to this, this will 177 * return the same float. This is expected to be called with a changing variable, e.g. {@code determine(++state)}, 178 * where the increment for state should be odd but otherwise doesn't really matter. This multiplies state by 179 * {@code 0x6C8E9CF570932BD5L} within this method, so using a small increment won't be much different from using a 180 * very large one, as long as it is odd. The period is 2 to the 64 if you increment or decrement by 1, but there are 181 * only 2 to the 30 possible floats between 0 and 1. 182 * @param state a variable that should be different every time you want a different random result; 183 * using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to 184 * generate numbers in reverse order 185 * @return a pseudo-random float between 0f (inclusive) and 1f (exclusive), determined by {@code state} 186 */ 187 public static float determineFloat(long state) { return (((state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23)) & 0xFFFFFF) * 0x1p-24f; } 188 189 190 /** 191 * Returns a random double that is deterministic based on state; if state is the same on two calls to this, this 192 * will return the same float. This is expected to be called with a changing variable, e.g. 193 * {@code determine(++state)}, where the increment for state should be odd but otherwise doesn't really matter. This 194 * multiplies state by {@code 0x6C8E9CF570932BD5L} within this method, so using a small increment won't be much 195 * different from using a very large one, as long as it is odd. The period is 2 to the 64 if you increment or 196 * decrement by 1, but there are only 2 to the 62 possible doubles between 0 and 1. 197 * @param state a variable that should be different every time you want a different random result; 198 * using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to 199 * generate numbers in reverse order 200 * @return a pseudo-random double between 0.0 (inclusive) and 1.0 (exclusive), determined by {@code state} 201 */ 202 public static double determineDouble(long state) { return (((state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23)) & 0x1FFFFFFFFFFFFFL) * 0x1p-53; } 203 204 /** 205 * Given a state that should usually change each time this is called, and a bound that limits the result to some 206 * (typically fairly small) int, produces a pseudo-random int between 0 and bound (exclusive). The bound can be 207 * negative, which will cause this to produce 0 or a negative int; otherwise this produces 0 or a positive int. 208 * The state should change each time this is called, generally by incrementing by an odd number (not an even number, 209 * especially not 0). It's fine to use {@code determineBounded(++state, bound)} to get a different int each time. 210 * The period is usually 2 to the 64 when you increment or decrement by 1, but some bounds may reduce the period (in 211 * the extreme case, a bound of 1 would force only 0 to be generated, so that would make the period 1). 212 * @param state a variable that should be different every time you want a different random result; 213 * using {@code determineBounded(++state, bound)} is recommended to go forwards or 214 * {@code determineBounded(--state, bound)} to generate numbers in reverse order 215 * @param bound the outer exclusive bound for the int this produces; can be negative or positive 216 * @return a pseudo-random int between 0 (inclusive) and bound (exclusive) 217 */ 218 public static int determineBounded(long state, final int bound) 219 { 220 return (int)((bound * ( 221 ((state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23)) 222 & 0xFFFFFFFFL)) >> 32); 223 } 224 225 /** 226 * Returns a random permutation of state; if state is the same on two calls to this, this will return the same 227 * number. This is expected to be called with some changing variable, e.g. {@code determine(state = state + 1 | 0)}, 228 * where the increment for state should be odd but otherwise doesn't really matter (the {@code | 0} is needed to 229 * force overflow to occur correctly on GWT; if you know you won't target GWT you can use {@code determine(++state)} 230 * instead). This multiplies state by {@code 0x62BD5} within this method, so using a small increment won't be 231 * much different from using a very large one, as long as it is odd. The period is 2 to the 32 if you increment or 232 * decrement by 1 (and perform any bitwise operation, such as {@code | 0}, if you might target GWT). If you use this 233 * on GWT and don't perform a bitwise operation on the new value for state, then the period will gradually shrink as 234 * precision is lost by the JavaScript double that GWT will use for state as a Java int. If you know that state will 235 * start at 0 and you call with {@code determine(++state)}, then on GWT you may not have to worry at all until 2 to 236 * the 34 calls have been made, after which state may cease to have the precision to represent an increase by 1 when 237 * the math inside this method is considered. The period will have been exhausted by that point anyway (4 times), so 238 * it's more of a concern if state may start at a much higher int. 239 * <br> 240 * This only uses int math, and should be fast on GWT. 241 * @param state a variable that should be different every time you want a different random result; 242 * using {@code determine(state = state + 1 | 0)} is recommended to go forwards or 243 * {@code determine(state = state - 1 | 0)} to generate numbers in reverse order 244 * @return a pseudo-random permutation of state 245 */ 246 public static int determineInt(int state) { 247 state = ((state *= 0x62BD5) ^ state >>> 13) * ((state & 0xFFFF8) ^ 0xCD7B5); 248 return ((state << 21) | (state >>> 11)) ^ (((state << 7) | (state >>> 25)) * 0x62BD5); 249 } 250 /** 251 * Given an int state that should usually change each time this is called, and a bound that limits the result to 252 * some (typically fairly small) int, produces a pseudo-random int between 0 and bound (exclusive). The bound should 253 * be between -65536 and 65535, that is, the range of a short. It can be negative, which will cause this to produce 254 * 0 or a negative int; otherwise this produces 0 or a positive int. The state should change each time this is 255 * called, generally by incrementing by an odd number (not an even number, especially not 0). It's fine to use 256 * {@code determineBounded(++state, bound)} to get a different int each time. The period is usually 2 to the 64 when 257 * you increment or decrement by 1, but some bounds may reduce the period (in the extreme case, a bound of 1 would 258 * force only 0 to be generated, so that would make the period 1). 259 * <br> 260 * This only uses int math, unlike other bounded determine() methods, but this requires the bound to be small. It 261 * should be very fast on GWT. 262 * @param state an int variable that should be different every time you want a different random result; 263 * using {@code determineBounded(++state, bound)} is recommended to go forwards or 264 * {@code determineBounded(--state, bound)} to generate numbers in reverse order 265 * @param bound the outer exclusive bound for the int this produces; should be between -65536 and 65535, inclusive 266 * @return a pseudo-random int between 0 (inclusive) and bound (exclusive) 267 */ 268 public static int determineBoundedShort(int state, final int bound) 269 { 270 state = ((state *= 0x62BD5) ^ state >>> 13) * ((state & 0xFFFF8) ^ 0xCD7B5); 271 return (((((state << 21) | (state >>> 11)) ^ (((state << 7) | (state >>> 25)) * 0x62BD5)) & 0xFFFF) * bound) >> 16; 272 } 273 /** 274 * Returns a random float that is deterministic based on an int state; if state is the same on two calls to this, 275 * this will return the same float. This is expected to be called with a changing variable, e.g. 276 * {@code determine(++state)}, where the increment for state should be odd but otherwise doesn't really matter. This 277 * multiplies state by {@code 0x62BD5} within this method, so using a small increment won't be much different from 278 * using a very large one, as long as it is odd. The period is 2 to the 32 if you increment or decrement by 1, but 279 * there are only 2 to the 30 possible floats between 0 and 1, and this can generate less than 2 to the 24 of them. 280 * <br> 281 * Except for the final conversion to float, this only uses int math, and should be fast on GWT. 282 * @param state an int variable that should be different every time you want a different random result; 283 * using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to 284 * generate numbers in reverse order 285 * @return a pseudo-random float between 0f (inclusive) and 1f (exclusive), determined by {@code state} 286 */ 287 public static float determineFloatFromInt(int state) { 288 state = ((state *= 0x62BD5) ^ state >>> 13) * ((state & 0xFFFF8) ^ 0xCD7B5); 289 return (((state << 21) | (state >>> 11)) ^ (((state << 7) | (state >>> 25)) * 0x62BD5) & 0xFFFFFF) * 0x1p-24f; 290 } 291 292} 293