001/* Written in 2016 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 xoroshiro64** generator; uses two 32-bit ints of state like {@link Lathe32RNG} 016 * but has better equidistribution. Starfish is 2-dimensionally equidistributed, so it can return all long values except 017 * for one, while Lathe is 1-dimensionally equidistributed so it can return all int values but not all longs. Starfish 018 * passes all 32TB of PractRand's statistical tests, and does so with no anomalies and no failures (the best possible 019 * outcome). It also passes at least one seed of TestU01's BigCrush in both forward and reverse with no failures. In 020 * statistical testing, xoroshiro128+ always fails some binary matrix rank tests, but that uses a pair of 64-bit states, 021 * and when the states are reduced to 32-bits, these small-word versions fail other tests as well. Starfish uses a 022 * simpler variant on xoroshiro64** that reduces some issues with that generator and trades them for better-understood 023 * issues. Starfish does not change xoroshiro's well-tested state transition, but it doesn't base the output on the sum 024 * of the two states (like xoroshiro128+), instead using the first state only for output (exactly like xoroshiro64** and 025 * similar to xoshiro256**). Any arithmetic it performs is safe for GWT. Starfish adds an extremely small amount of 026 * extra code to xoroshiro, running xoroshiro's state transition as normal, using stateA (or s[0] in the original 027 * xoroshiro code) multiplied by 31 as the initial result, then bitwise-rotating that initial result by 28 and adding a 028 * constant that is close to 2 to the 32 times the golden ratio, specifically {@code 0x9E3779BD}. Although no bits of 029 * xoroshiro are truly free of artifacts, some are harder to find issues with 030 * (see <a href="http://www.pcg-random.org/posts/xoroshiro-fails-truncated.html">this article by PCG-Random's author</a> 031 * for more detail). It is unclear if the changes made here would improve the larger-state version, but they probably 032 * would help to some extent with at least the binary rank failures. The period is identical to xoroshiro with two 033 * 32-bit states, at 0xFFFFFFFFFFFFFFFF or 2 to the 64 minus 1. This generator is a little slower than xoroshiro64+ or 034 * Lathe, but has better distribution than either. It is equivalent to the algorithm used in {@link GWTRNG}. 035 * <br> 036 * This avoids an issue in xoroshiro** generators where many multipliers, when applied to the output of a xoroshiro** 037 * generator, will cause the modified output to rapidly fail binary matrix rank tests. It has its own issue where 038 * subtracting {@code 0x9E3779BD} or a number with a low Hamming distance from {@code 0x9E3779BD} from every output will 039 * cause similar binary matrix rank failures. It should be clear that this is not a cryptographic generator, but I am 040 * not claiming this is a rock-solid or all-purpose generator either; if a hostile user is trying to subvert a Starfish 041 * generator and can access full outputs, it is a cakewalk to find or create issues. 042 * <br> 043 * The name comes from the single Star operation used (relative to the StarStar scrambler) and the addition of the 044 * golden ratio, or phi, which sounds close to fish. 045 * <br> 046 * <a href="http://xoshiro.di.unimi.it/xoroshiro64starstar.c">Original version here for xoroshiro64**</a>. 047 * <br> 048 * Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) 049 * Ported and modified in 2018 by Tommy Ettinger 050 * @author Sebastiano Vigna 051 * @author David Blackman 052 * @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) 053 */ 054public final class Starfish32RNG implements StatefulRandomness, Serializable { 055 056 private static final long serialVersionUID = 2L; 057 058 private int stateA, stateB; 059 060 /** 061 * Creates a new generator seeded using two calls to Math.random(). 062 */ 063 public Starfish32RNG() { 064 setState((int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000)); 065 } 066 /** 067 * Constructs this Lathe32RNG by dispersing the bits of seed using {@link #setSeed(int)} across the two parts of state 068 * this has. 069 * @param seed an int that won't be used exactly, but will affect both components of state 070 */ 071 public Starfish32RNG(final int seed) { 072 setSeed(seed); 073 } 074 /** 075 * Constructs this Lathe32RNG by splitting the given seed across the two parts of state this has with 076 * {@link #setState(long)}. 077 * @param seed a long that will be split across both components of state 078 */ 079 public Starfish32RNG(final long seed) { 080 setState(seed); 081 } 082 /** 083 * Constructs this Lathe32RNG by calling {@link #setState(int, int)} on stateA and stateB as given; see that method 084 * for the specific details (stateA and stateB are kept as-is unless they are both 0). 085 * @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0 086 * @param stateB the number to use as the second part of the state 087 */ 088 public Starfish32RNG(final int stateA, final int stateB) { 089 setState(stateA, stateB); 090 } 091 092 @Override 093 public final int next(int bits) { 094 final int s0 = stateA; 095 final int s1 = stateB ^ s0; 096 final int result = s0 * 31; 097 stateA = (s0 << 26 | s0 >>> 6) ^ s1 ^ (s1 << 9); 098 stateB = (s1 << 13 | s1 >>> 19); 099 return (result << 28 | result >>> 4) + 0x9E3779BD >>> (32 - bits); 100 } 101 102 /** 103 * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer. 104 * @return any int, all 32 bits are random 105 */ 106 public final int nextInt() { 107 final int s0 = stateA; 108 final int s1 = stateB ^ s0; 109 final int result = s0 * 31; 110 stateA = (s0 << 26 | s0 >>> 6) ^ s1 ^ (s1 << 9); 111 stateB = (s1 << 13 | s1 >>> 19); 112 return (result << 28 | result >>> 4) + 0x9E3779BD; 113 } 114 115 @Override 116 public final long nextLong() { 117 int s0 = stateA; 118 int s1 = stateB ^ s0; 119 final int high = s0 * 31; 120 s0 = (s0 << 26 | s0 >>> 6) ^ s1 ^ (s1 << 9); 121 s1 = (s1 << 13 | s1 >>> 19) ^ s0; 122 final int low = s0 * 31; 123 stateA = (s0 << 26 | s0 >>> 6) ^ s1 ^ (s1 << 9); 124 stateB = (s1 << 13 | s1 >>> 19); 125 return ((high << 28 | high >>> 4) + 0x9E3779BDL) << 32 126 | ((low << 28 | low >>> 4) + 0x9E3779BD & 0xFFFFFFFFL); 127 } 128 129 /** 130 * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the 131 * copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to 132 * copy the state so it isn't shared, usually, and produce a new value with the same exact state. 133 * 134 * @return a copy of this RandomnessSource 135 */ 136 @Override 137 public Starfish32RNG copy() { 138 return new Starfish32RNG(stateA, stateB); 139 } 140 141 /** 142 * Sets the state of this generator using one int, running it through Zog32RNG's algorithm two times to get 143 * two ints. If the states would both be 0, state A is assigned 1 instead. 144 * @param seed the int to use to produce this generator's state 145 */ 146 public void setSeed(final int seed) { 147 int z = seed + 0xC74EAD55, a = seed ^ z; 148 a ^= a >>> 14; 149 z = (z ^ z >>> 10) * 0xA5CB3; 150 a ^= a >>> 15; 151 stateA = (z ^ z >>> 20) + (a ^= a << 13); 152 z = seed + 0x8E9D5AAA; 153 a ^= a >>> 14; 154 z = (z ^ z >>> 10) * 0xA5CB3; 155 a ^= a >>> 15; 156 stateB = (z ^ z >>> 20) + (a ^ a << 13); 157 if((stateA | stateB) == 0) 158 stateA = 1; 159 } 160 161 public int getStateA() 162 { 163 return stateA; 164 } 165 /** 166 * Sets the first part of the state to the given int. As a special case, if the parameter is 0 and stateB is 167 * already 0, this will set stateA to 1 instead, since both states cannot be 0 at the same time. Usually, you 168 * should use {@link #setState(int, int)} to set both states at once, but the result will be the same if you call 169 * setStateA() and then setStateB() or if you call setStateB() and then setStateA(). 170 * @param stateA any int 171 */ 172 173 public void setStateA(int stateA) 174 { 175 this.stateA = (stateA | stateB) == 0 ? 1 : stateA; 176 } 177 public int getStateB() 178 { 179 return stateB; 180 } 181 182 /** 183 * Sets the second part of the state to the given int. As a special case, if the parameter is 0 and stateA is 184 * already 0, this will set stateA to 1 and stateB to 0, since both cannot be 0 at the same time. Usually, you 185 * should use {@link #setState(int, int)} to set both states at once, but the result will be the same if you call 186 * setStateA() and then setStateB() or if you call setStateB() and then setStateA(). 187 * @param stateB any int 188 */ 189 public void setStateB(int stateB) 190 { 191 this.stateB = stateB; 192 if((stateB | stateA) == 0) stateA = 1; 193 } 194 195 /** 196 * Sets the current internal state of this Lathe32RNG with three ints, where stateA and stateB can each be any int 197 * unless they are both 0 (which will be treated as if stateA is 1 and stateB is 0). 198 * @param stateA any int (if stateA and stateB are both 0, this will be treated as 1) 199 * @param stateB any int 200 */ 201 public void setState(int stateA, int stateB) 202 { 203 this.stateA = (stateA | stateB) == 0 ? 1 : stateA; 204 this.stateB = stateB; 205 } 206 207 /** 208 * Get the current internal state of the StatefulRandomness as a long. 209 * 210 * @return the current internal state of this object. 211 */ 212 @Override 213 public long getState() { 214 return (stateA & 0xFFFFFFFFL) | ((long)stateB) << 32; 215 } 216 217 /** 218 * Set the current internal state of this StatefulRandomness with a long. 219 * 220 * @param state a 64-bit long. You should avoid passing 0; this implementation will treat it as 1. 221 */ 222 @Override 223 public void setState(long state) { 224 stateA = state == 0 ? 1 : (int)(state & 0xFFFFFFFFL); 225 stateB = (int)(state >>> 32); 226 } 227 228 @Override 229 public String toString() { 230 return "Starfish32RNG with stateA 0x" + StringKit.hex(stateA) + " and stateB 0x" + StringKit.hex(stateB); 231 } 232 233 @Override 234 public boolean equals(Object o) { 235 if (this == o) return true; 236 if (o == null || getClass() != o.getClass()) return false; 237 238 Starfish32RNG starfish32RNG = (Starfish32RNG) o; 239 240 if (stateA != starfish32RNG.stateA) return false; 241 return stateB == starfish32RNG.stateB; 242 } 243 244 @Override 245 public int hashCode() { 246 return 31 * stateA + stateB; 247 } 248}