001package squidpony.squidmath; 002 003import squidpony.StringKit; 004 005import java.io.Serializable; 006 007/** 008 * A high-quality StatefulRandomness based on {@link LinnormRNG} but modified to allow any odd number as a stream, 009 * instead of LinnormRNG's hardcoded stream of 1. Although some streams may have quality issues, the structure is based 010 * on a linear congruential generator where the stream is the additive component, and in that context all odd numbers 011 * are usually considered equally effective. Has 64 bits of state, 64 bits used to store a stream (which cannot be 012 * changed after construction) and natively outputs 64 bits at a time. Changes its state with a basic linear 013 * congruential generator (it is simply {@code state = state * 3935559000370003845L + stream}). Starting with that LCG's 014 * output, it xorshifts that output twice, multiplies by a very large negative long, then returns another xorshift. Like 015 * LinnormRNG, the output of this simple function passes all 32TB of PractRand (for one stream, it had 3 anomalies, but 016 * another had none, and none were ever significant or persistent), meaning its statistical quality is excellent. The 017 * speed of this particular class isn't fully clear yet, but benchmarks performed under the heavy load of PractRand 018 * testing happening at the same time appeared to show no significant difference between LinnormRNG and MizuchiRNG in 019 * speed (which means it's tied for second place in its category, behind {@link DiverRNG}). 020 * <br> 021 * This generator is a StatefulRandomness but not a SkippingRandomness, so it can't (efficiently) have the skip() method 022 * that LightRNG has. A method could be written to run the generator's state backwards, though, as well as to get the 023 * state from an output of {@link #nextLong()}. {@link LinnormRNG} uses the same algorithm except for the number added 024 * in the LCG state update; there this number is always 1, but here it can be any odd long. This means that any given 025 * MizuchiRNG object has two long values stored in it instead of the one in a LinnormRNG, but it allows two MizuchiRNG 026 * objects with different streams to produce different, probably-not-correlated sequences of results, even with the same 027 * seed. This property may be useful for cases where an adversary is trying to predict results in some way, though using 028 * different streams for this purpose isn't enough and should be coupled with truncation of a large part of output (see 029 * PCG-Random's techniques for this). 030 * <br> 031 * The name comes from combining the concept of a linnorm, which is a dragon and the namesake of LinnormRNG, with 032 * streams, since Mizuchi allows many possible streams, to get the concept of a river-or-stream-dwelling dragon. The 033 * mizuchi is a (by some versions of the story) river dragon from Japanese mythology. 034 * <br> 035 * Written June 29, 2019 by Tommy Ettinger. Thanks to M.E. O'Neill for her insights into the family of generators both 036 * this and her PCG-Random fall into, and to the team that worked on SplitMix64 for SplittableRandom in JDK 8. Chris 037 * Doty-Humphrey's work on PractRand has been invaluable. The LCG state multiplier is listed in a paper by L'Ecuyer from 038 * 1999, Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure. The other 039 * multiplier is from PCG-Random, and that's both the nothing-up-my-sleeve numbers used here. Thanks also to Sebastiano 040 * Vigna and David Blackwell for creating the incredibly fast xoroshiro128+ generator and also very fast 041 * <a href="http://xoshiro.di.unimi.it/hwd.php">HWD tool</a>; the former inspired me to make my code even faster and the 042 * latter tool seems useful so far in proving the quality of the generator (LinnormRNG passes over 100TB of HWD, and 043 * probably would pass much more if I gave it more days to run). 044 * @author Tommy Ettinger 045 */ 046public final class MizuchiRNG implements StatefulRandomness, Serializable { 047 048 private static final long serialVersionUID = 153186732328748834L; 049 050 private long state; /* The state can be seeded with any value. */ 051 052 private final long stream; 053 054 /** 055 * Creates a new generator seeded using Math.random. 056 */ 057 public MizuchiRNG() { 058 this((long) ((Math.random() - 0.5) * 0x10000000000000L) 059 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L), 060 (long) ((Math.random() - 0.5) * 0x10000000000000L) 061 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L)); 062 } 063 064 public MizuchiRNG(final long seed) { 065 state = seed; 066 this.stream = (seed 067 ^ Long.rotateLeft((seed ^ 0x369DEA0F31A53F85L) * 0x6A5D39EAE116586DL + 0x9E3779B97F4A7C15L, (int)seed) 068 ^ Long.rotateLeft((seed ^ 0x6A5D39EAE116586DL) * 0x369DEA0F31A53F85L + 0x4A7C159E3779B97FL, (int)seed * 0x41C64E6D >>> 26)) | 1L; 069 } 070 071 public MizuchiRNG(final long seed, final long stream) { 072 state = seed; 073 this.stream = (stream | 1L); 074 } 075 076 public MizuchiRNG(final String seed) { 077 state = CrossHash.Mist.predefined[32].hash64(seed); 078 stream = (CrossHash.Mist.predefined[(int) state & 31].hash64(seed) | 1L); 079 } 080 081 @Override 082 public final int next(int bits) 083 { 084 long z = (state = state * 0x369DEA0F31A53F85L + stream); 085 z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L; 086 return (int)(z ^ z >>> 25) >>> (32 - bits); 087 } 088 089 /** 090 * Can return any long, positive or negative, of any size permissible in a 64-bit signed integer. 091 * 092 * @return any long, all 64 bits are random 093 */ 094 @Override 095 public final long nextLong() { 096 long z = (state = state * 0x369DEA0F31A53F85L + stream); 097 z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L; 098 return (z ^ z >>> 25); 099 } 100 101 /** 102 * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the 103 * copy, both will generate the same sequence of random numbers from the point copy() was called. This just need to 104 * copy the state so it isn't shared, usually, and produce a new value with the same exact state. 105 * 106 * @return a copy of this RandomnessSource 107 */ 108 @Override 109 public MizuchiRNG copy() { 110 return new MizuchiRNG(state); 111 } 112 113 /** 114 * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer. 115 * 116 * @return any int, all 32 bits are random 117 */ 118 public final int nextInt() { 119 long z = (state = state * 0x369DEA0F31A53F85L + stream); 120 z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L; 121 return (int)(z ^ z >>> 25); 122 } 123 124 /** 125 * Exclusive on the outer bound. The inner bound is 0. 126 * The bound can be negative, which makes this produce either a negative int or 0. 127 * 128 * @param bound the upper bound; should be positive 129 * @return a random int between 0 (inclusive) and bound (exclusive) 130 */ 131 public final int nextInt(final int bound) { 132 long z = (state = state * 0x369DEA0F31A53F85L + stream); 133 z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L; 134 return (int)((bound * ((z ^ z >>> 25) & 0xFFFFFFFFL)) >> 32); 135 } 136 137 /** 138 * Inclusive inner, exclusive outer. 139 * 140 * @param inner the inner bound, inclusive, can be positive or negative 141 * @param outer the outer bound, exclusive, can be positive or negative, usually greater than inner 142 * @return a random int between inner (inclusive) and outer (exclusive) 143 */ 144 public final int nextInt(final int inner, final int outer) { 145 return inner + nextInt(outer - inner); 146 } 147 148 /** 149 * Exclusive on the upper bound. The lower bound is 0. 150 * 151 * @param bound the upper bound; should be positive (if negative, this returns 0) 152 * @return a random long less than n 153 */ 154 public final long nextLong(long bound) { 155 long rand = nextLong(); 156 if (bound <= 0) return 0; 157 final long randLow = rand & 0xFFFFFFFFL; 158 final long boundLow = bound & 0xFFFFFFFFL; 159 rand >>>= 32; 160 bound >>>= 32; 161 final long a = rand * bound; 162 final long b = randLow * boundLow; 163 return (((b >>> 32) + (rand + randLow) * (bound + boundLow) - a - b) >>> 32) + a; 164 } 165 166 /** 167 * Inclusive lower, exclusive upper. 168 * 169 * @param lower the lower bound, inclusive, can be positive or negative 170 * @param upper the upper bound, exclusive, should be positive, must be greater than lower 171 * @return a random long at least equal to lower and less than upper 172 */ 173 public final long nextLong(final long lower, final long upper) { 174 if (upper - lower <= 0) throw new IllegalArgumentException("Upper bound must be greater than lower bound"); 175 return lower + nextLong(upper - lower); 176 } 177 178 /** 179 * Gets a uniform random double in the range [0.0,1.0) 180 * 181 * @return a random double at least equal to 0.0 and less than 1.0 182 */ 183 public final double nextDouble() { 184 long z = (state = state * 0x369DEA0F31A53F85L + stream); 185 z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L; 186 return ((z ^ z >>> 25) & 0x1FFFFFFFFFFFFFL) * 0x1p-53; 187 188 } 189 190 /** 191 * Gets a uniform random double in the range [0.0,outer) given a positive parameter outer. If outer 192 * is negative, it will be the (exclusive) lower bound and 0.0 will be the (inclusive) upper bound. 193 * 194 * @param outer the exclusive outer bound, can be negative 195 * @return a random double between 0.0 (inclusive) and outer (exclusive) 196 */ 197 public final double nextDouble(final double outer) { 198 long z = (state = state * 0x369DEA0F31A53F85L + stream); 199 z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L; 200 return ((z ^ z >>> 25) & 0x1FFFFFFFFFFFFFL) * 0x1p-53 * outer; 201 } 202 203 /** 204 * Gets a uniform random float in the range [0.0,1.0) 205 * 206 * @return a random float at least equal to 0.0 and less than 1.0 207 */ 208 public final float nextFloat() { 209 final long z = (state = state * 0x369DEA0F31A53F85L + stream); 210 return ((z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L >>> 40) * 0x1p-24f; 211 } 212 213 /** 214 * Gets a random value, true or false. 215 * Calls nextLong() once. 216 * 217 * @return a random true or false value. 218 */ 219 public final boolean nextBoolean() { 220 final long z = (state = state * 0x369DEA0F31A53F85L + stream); 221 return ((z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L) < 0; 222 } 223 224 /** 225 * Given a byte array as a parameter, this will fill the array with random bytes (modifying it 226 * in-place). Calls nextLong() {@code Math.ceil(bytes.length / 8.0)} times. 227 * 228 * @param bytes a byte array that will have its contents overwritten with random bytes. 229 */ 230 public final void nextBytes(final byte[] bytes) { 231 int i = bytes.length, n; 232 while (i != 0) { 233 n = Math.min(i, 8); 234 for (long bits = nextLong(); n-- != 0; bits >>>= 8) bytes[--i] = (byte) bits; 235 } 236 } 237 238 /** 239 * Sets the seed (also the current state) of this generator. 240 * 241 * @param seed the seed to use for this LightRNG, as if it was constructed with this seed. 242 */ 243 @Override 244 public final void setState(final long seed) { 245 state = seed; 246 } 247 248 /** 249 * Gets the current state of this generator. 250 * 251 * @return the current seed of this LightRNG, changed once per call to nextLong() 252 */ 253 @Override 254 public final long getState() { 255 return state; 256 } 257 258 @Override 259 public String toString() { 260 return "MizuchiRNG with state 0x" + StringKit.hex(state) + "L on stream 0x" + StringKit.hex(stream) + 'L'; 261 } 262 263 @Override 264 public boolean equals(Object o) { 265 if (this == o) return true; 266 if (o == null || getClass() != o.getClass()) return false; 267 MizuchiRNG mizuchiRNG = ((MizuchiRNG) o); 268 return state == mizuchiRNG.state && stream == mizuchiRNG.stream; 269 } 270 271 @Override 272 public int hashCode() { 273 return (int) ((state ^ (state >>> 32)) * 0xDB4F0B9175AE2165L + (stream ^ (stream >>> 32))); 274 } 275 276// public static void main(String[] args) 277// { 278// /* 279// cd target/classes 280// java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly sarong/DervishRNG > Dervish_asm.txt 281// */ 282// long longState = 1L; 283// int intState = 1; 284// float floatState = 0f; 285// double doubleState = 0.0; 286// MizuchiRNG rng = new MizuchiRNG(1L, 123456789L); 287// //longState += determine(i); 288// //longState = longState + 0x9E3779B97F4A7C15L; 289// //seed += determine(longState++); 290// for (int r = 0; r < 10; r++) { 291// for (int i = 0; i < 10000007; i++) { 292// longState += rng.nextLong(); 293// } 294// } 295// System.out.println(longState); 296// 297// for (int r = 0; r < 10; r++) { 298// for (int i = 0; i < 10000007; i++) { 299// intState += rng.next(16); 300// } 301// } 302// System.out.println(intState); 303// 304// for (int r = 0; r < 10; r++) { 305// for (int i = 0; i < 10000007; i++) { 306// floatState += rng.nextFloat(); 307// } 308// } 309// System.out.println(floatState); 310// 311// for (int r = 0; r < 10; r++) { 312// for (int i = 0; i < 10000007; i++) { 313// doubleState += rng.nextDouble(); 314// } 315// } 316// System.out.println(doubleState); 317// 318// } 319 320}