001/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) 002 003To the extent possible under law, the author has dedicated all copyright 004and related and neighboring rights to this software to the public domain 005worldwide. This software is distributed without any warranty. 006 007See <http://creativecommons.org/publicdomain/zero/1.0/>. */ 008package squidpony.squidmath; 009 010import squidpony.StringKit; 011 012import java.io.Serializable; 013 014/** 015 * A modification of Blackman and Vigna's xoshiro128 generator with a different "scrambler" than the default; this 016 * generator has four 32-bit states and passes at least 32TB of PractRand (with one "unusual" anomaly at 4TB). It is 017 * four-dimensionally equidistributed, which is an uncommon feature of a PRNG, and means every output is equally likely 018 * not just when one value is generated with {@link #nextInt()}, but also that when up to four 32-bit values are 019 * generated and treated as up to a 128-bit output, then all possible 128-bit outputs are equally likely (with the 020 * exception of the 128-bit value 0x9E3779BD9E3779BD9E3779BD9E3779BD, which won't ever be generated as a group even 021 * though 0x9E3779BD can occur up to three times in four results). The scrambler simply multiplies a state variable by 022 * 31, rotates that value left by 23, and adds a number obtained from the golden ratio, phi (0x9E3779BD). It may have 023 * all sorts of issues since this scrambler hasn't been analyzed much, but 128 bits of state help make most issues less 024 * severe, and the same scrambler works well for xoroshiro with 32-bit states (used in {@link Starfish32RNG}). A 025 * clear known flaw is that if you subtract the same golden-ratio-based number from each result, the resulting modified 026 * generator will quickly fail binary matrix rank tests. This could be ameliorated by employing a fifth state variable 027 * that increments in a Weyl sequence, which is what {@link Oriole32RNG} does, and adding that instead of the golden 028 * ratio, though this would eliminate the 4-dimensional equidistribution. XoshiroStarPhi32RNG is optimized for GWT, 029 * like {@link Lathe32RNG} and {@link Starfish32RNG}, which means any non-bitwise math in the source is followed 030 * by bitwise math later, and this sometimes can result in obtuse-looking code along the lines of 031 * {@code int foo = bar + 0x9E3779BD | 0;}. 032 * <br> 033 * This generator seems to be a little faster than xoshiro with the StarStar scrambler, while offering the same period 034 * and distribution. It does not have one group of vulnerabilities held by the "StarStar" scrambler, where multiplying 035 * the result by numbers even somewhat similar to the modulus-2-to-the-32 multiplicative inverse of the last multiplier 036 * used in the StarStar scrambler usually results in a binary rank failure in as little as 512MB of PractRand testing. 037 * As far as I can tell, that failure occurs in the StarStar version whenever the output is reliably multiplied by an 038 * integer where the last byte is 0x39 (or 57 in decimal), additionally affects at least some multipliers that have 039 * their last 7 bits equal to 0b0111001 (the same as in 0x39 before, but requiring only 7 bits to be equivalent), and 040 * this seems to be related to the choice of rotation amount (the StarStar scrambler rotates by 7 places). This 041 * generator does have a different vulnerability when a specific number is subtracted from the output each time (for the 042 * purpose of transparency, 0x9E3779BD). This flaw may occur with similar subtracted numbers as well, probably affecting 043 * any subtrahends with a low Hamming distance from 0x9E3779BD, considering less-significant bits as more relevant to 044 * the distance than more-significant bits. 045 * <br> 046 * <a href="http://xoshiro.di.unimi.it/xoshiro128starstar.c">Original version here for xoshiro128**</a>, by Sebastiano 047 * Vigna and David Blackman. 048 * <br> 049 * Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) 050 * StarPhi scrambler written in 2018 by Tommy Ettinger 051 * @author Sebastiano Vigna 052 * @author David Blackman 053 * @author Tommy Ettinger (if there's a flaw, use SquidLib's or Sarong's issues and don't bother Vigna or Blackman, it's probably a mistake in SquidLib's implementation) 054 */ 055public final class XoshiroStarPhi32RNG implements RandomnessSource, Serializable { 056 057 private static final long serialVersionUID = 1L; 058 059 private int stateA, stateB, stateC, stateD; 060 061 /** 062 * Creates a new generator seeded using four calls to Math.random(). 063 */ 064 public XoshiroStarPhi32RNG() { 065 setState((int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000), 066 (int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000)); 067 } 068 /** 069 * Constructs this XoshiroStarPhi32RNG by dispersing the bits of seed using {@link #setSeed(int)} across the four 070 * parts of state this has. 071 * @param seed an int that won't be used exactly, but will affect all components of state 072 */ 073 public XoshiroStarPhi32RNG(final int seed) { 074 setSeed(seed); 075 } 076 /** 077 * Constructs this XoshiroStarPhi32RNG by dispersing the bits of seed using {@link #setSeed(long)} across the four 078 * parts of state this has. 079 * @param seed a long that will be split across all components of state 080 */ 081 public XoshiroStarPhi32RNG(final long seed) { 082 setSeed(seed); 083 } 084 /** 085 * Constructs this XoshiroStarPhi32RNG by calling {@link #setState(int, int, int, int)} on stateA and stateB as 086 * given; see that method for the specific details (the states are kept as-is unless they are all 0). 087 * @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0 088 * @param stateB the number to use as the second part of the state 089 * @param stateC the number to use as the third part of the state 090 * @param stateD the number to use as the fourth part of the state 091 */ 092 public XoshiroStarPhi32RNG(final int stateA, final int stateB, final int stateC, final int stateD) { 093 setState(stateA, stateB, stateC, stateD); 094 } 095 096 @Override 097 public final int next(int bits) { 098 final int result = stateB * 31; 099 final int t = stateB << 9; 100 stateC ^= stateA; 101 stateD ^= stateB; 102 stateB ^= stateC; 103 stateA ^= stateD; 104 stateC ^= t; 105 stateD = (stateD << 11 | stateD >>> 21); 106 return (result << 23 | result >>> 9) + 0x9E3779BD >>> (32 - bits); 107 } 108 109 /** 110 * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer. 111 * @return any int, all 32 bits are random 112 */ 113 public final int nextInt() { 114 final int result = stateB * 31; 115 final int t = stateB << 9; 116 stateC ^= stateA; 117 stateD ^= stateB; 118 stateB ^= stateC; 119 stateA ^= stateD; 120 stateC ^= t; 121 stateD = (stateD << 11 | stateD >>> 21); 122 return (result << 23 | result >>> 9) + 0x9E3779BD | 0; 123 } 124 125 @Override 126 public final long nextLong() { 127 int result = stateB * 31; 128 int t = stateB << 9; 129 stateC ^= stateA; 130 stateD ^= stateB; 131 stateB ^= stateC; 132 stateA ^= stateD; 133 stateC ^= t; 134 long high = (result << 23 | result >>> 9) + 0x9E3779BD; 135 stateD = (stateD << 11 | stateD >>> 21); 136 result = stateB * 31; 137 t = stateB << 9; 138 stateC ^= stateA; 139 stateD ^= stateB; 140 stateB ^= stateC; 141 stateA ^= stateD; 142 stateC ^= t; 143 stateD = (stateD << 11 | stateD >>> 21); 144 return high << 32 ^ ((result << 23 | result >>> 9) + 0x9E3779BD); 145 } 146 147 /** 148 * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the 149 * copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to 150 * copy the state so it isn't shared, usually, and produce a new value with the same exact state. 151 * 152 * @return a copy of this RandomnessSource 153 */ 154 @Override 155 public XoshiroStarPhi32RNG copy() { 156 return new XoshiroStarPhi32RNG(stateA, stateB, stateC, stateD); 157 } 158 159 /** 160 * Sets the state of this generator using one int, running it through a GWT-compatible variant of SplitMix32 four 161 * times to get four ints of state, all guaranteed to be different. 162 * @param seed the int to use to produce this generator's states 163 */ 164 public void setSeed(final int seed) { 165 int z = seed + 0xC74EAD55; 166 z = (z ^ (z >>> 16)) * 0x85A6B; 167 z = (z ^ (z >>> 13)) * 0xCAE35; 168 stateA = z ^ (z >>> 16); 169 z = seed + 0x8E9D5AAA; 170 z = (z ^ (z >>> 16)) * 0x85A6B; 171 z = (z ^ (z >>> 13)) * 0xCAE35; 172 stateB = z ^ (z >>> 16); 173 z = seed + 0x55EC07FF; 174 z = (z ^ (z >>> 16)) * 0x85A6B; 175 z = (z ^ (z >>> 13)) * 0xCAE35; 176 stateC = z ^ (z >>> 16); 177 z = seed + 0x1D3AB554; 178 z = (z ^ (z >>> 16)) * 0x85A6B; 179 z = (z ^ (z >>> 13)) * 0xCAE35; 180 stateD = z ^ (z >>> 16); 181 } 182 183 /** 184 * Sets the state of this generator using one long, running it through a GWT-compatible variant of SplitMix32 four 185 * times to get four ints of state, guaranteed to repeat a state no more than two times. 186 * @param seed the long to use to produce this generator's states 187 */ 188 public void setSeed(final long seed) { 189 int z = (int)((seed & 0xFFFFFFFFL) + 0xC74EAD55); 190 z = (z ^ (z >>> 16)) * 0x85A6B; 191 z = (z ^ (z >>> 13)) * 0xCAE35; 192 stateA = z ^ (z >>> 16); 193 z = (int)((seed & 0xFFFFFFFFL) + 0x8E9D5AAA); 194 z = (z ^ (z >>> 16)) * 0x85A6B; 195 z = (z ^ (z >>> 13)) * 0xCAE35; 196 stateB = z ^ (z >>> 16); 197 z = (int)((seed >>> 32) + 0xC74EAD55); 198 z = (z ^ (z >>> 16)) * 0x85A6B; 199 z = (z ^ (z >>> 13)) * 0xCAE35; 200 stateC = z ^ (z >>> 16); 201 z = (int)((seed >>> 32) + 0x8E9D5AAA); 202 z = (z ^ (z >>> 16)) * 0x85A6B; 203 z = (z ^ (z >>> 13)) * 0xCAE35; 204 stateD = z ^ (z >>> 16); 205 } 206 207 public int getStateA() 208 { 209 return stateA; 210 } 211 /** 212 * Sets the first part of the state to the given int. As a special case, if the parameter is 0 and this would set 213 * all states to be 0, this will set stateA to 1 instead. Usually, you should use 214 * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set 215 * the four states individually. 216 * @param stateA any int 217 */ 218 public void setStateA(int stateA) 219 { 220 this.stateA = (stateA | stateB | stateC | stateD) == 0 ? 1 : stateA; 221 } 222 public int getStateB() 223 { 224 return stateB; 225 } 226 227 /** 228 * Sets the second part of the state to the given int. As a special case, if the parameter is 0 and this would set 229 * all states to be 0, this will set stateA to 1 in addition to setting stateB to 0. Usually, you should use 230 * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set 231 * the four states individually. 232 * @param stateB any int 233 */ 234 public void setStateB(int stateB) 235 { 236 this.stateB = stateB; 237 if((stateA | stateB | stateC | stateD) == 0) stateA = 1; 238 } 239 public int getStateC() 240 { 241 return stateC; 242 } 243 244 /** 245 * Sets the third part of the state to the given int. As a special case, if the parameter is 0 and this would set 246 * all states to be 0, this will set stateA to 1 in addition to setting stateC to 0. Usually, you should use 247 * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set 248 * the four states individually. 249 * @param stateC any int 250 */ 251 public void setStateC(int stateC) 252 { 253 this.stateC = stateC; 254 if((stateA | stateB | stateC | stateD) == 0) stateA = 1; 255 } 256 257 public int getStateD() 258 { 259 return stateD; 260 } 261 262 /** 263 * Sets the second part of the state to the given int. As a special case, if the parameter is 0 and this would set 264 * all states to be 0, this will set stateA to 1 in addition to setting stateD to 0. Usually, you should use 265 * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set 266 * the four states individually. 267 * @param stateD any int 268 */ 269 public void setStateD(int stateD) 270 { 271 this.stateD = stateD; 272 if((stateA | stateB | stateC | stateD) == 0) stateA = 1; 273 } 274 275 /** 276 * Sets the current internal state of this XoshiroStarPhi32RNG with four ints, where each can be any int unless 277 * they are all 0 (which will be treated as if stateA is 1 and the rest are 0). 278 * @param stateA any int (if all parameters are both 0, this will be treated as 1) 279 * @param stateB any int 280 * @param stateC any int 281 * @param stateD any int 282 */ 283 public void setState(final int stateA, final int stateB, final int stateC, final int stateD) 284 { 285 this.stateA = (stateA | stateB | stateC | stateD) == 0 ? 1 : stateA; 286 this.stateB = stateB; 287 this.stateC = stateC; 288 this.stateD = stateD; 289 } 290 291 @Override 292 public String toString() { 293 return "XoshiroStarPhi32RNG with stateA 0x" + StringKit.hex(stateA) + ", stateB 0x" + StringKit.hex(stateB) 294 + ", stateC 0x" + StringKit.hex(stateC) + ", and stateD 0x" + StringKit.hex(stateD); 295 } 296 297 @Override 298 public boolean equals(Object o) { 299 if (this == o) return true; 300 if (o == null || getClass() != o.getClass()) return false; 301 302 XoshiroStarPhi32RNG xoshiroStarPhi32RNG = (XoshiroStarPhi32RNG) o; 303 304 return stateA == xoshiroStarPhi32RNG.stateA && stateB == xoshiroStarPhi32RNG.stateB && 305 stateC == xoshiroStarPhi32RNG.stateC && stateD == xoshiroStarPhi32RNG.stateD; 306 } 307 308 @Override 309 public int hashCode() { 310 return 31 * (31 * (31 * stateA + stateB) + stateC) + stateD | 0; 311 } 312}