001package squidpony.squidmath; 002 003import squidpony.StringKit; 004 005import java.io.Serializable; 006 007/** 008 * A larger-period generator with 128 bits of state, good speed, and high quality in PractRand testing; it is at least 009 * 1-dimensionally equidistributed. It appears to be slightly faster than a Xorshift128+ generator, like RandomXS128 in 010 * libGDX, with practically the same period (this has a period of 2 to the 128), but it isn't as fast as as 011 * {@link OrbitRNG} or {@link GearRNG} (Goat seems to have higher statistical quality than either of those late in 012 * testing, though). It passes 64TB of PractRand testing with no anomalies, and might be able to endure tests past even 013 * that (the default setting stops at 32TB); I had set up PractRand to test up to 128TB but it ran out of memory after 014 * 5 days of nonstop testing on all 6 cores. If 16GB of RAM isn't enough to find even an anomaly in GoatRNG, then it is 015 * probably quite good. 016 * <br> 017 * Unlike most RNGs from outside Goat, Gear, and Orbit's family, this relies on a conditional and comparison to achieve 018 * both its period and randomness goals. All of these generators use two additive sequences for their states, and stall 019 * one of the state updates when the other state matches a criterion. For Orbit, it stalls only when stateA is 0 020 * (roughly 1 in 18 quintillion generated numbers); for Gear, stateA must be less than 1863783533 away from the minimum 021 * long value (roughly 1 in 10 billion generated numbers), and here, stateA must be less than 5096992405936522019L to 022 * stall (roughly 3 in 4 generated numbers). 023 * <br> 024 * Unlike GearRNG, this allows all long values for both states; unlike OrbitRNG, there shouldn't be significant 025 * correlation between an even value for stateB and the value 1 greater than that (such as 4 and 5, or 100 and 101). 026 * <br> 027 * The name comes from how goats are reliably hard to predict, like an RNG should be. 028 * It is called GhoulRNG in some tests run on it; an earlier version of GoatRNG also exists 029 * that does well in testing for the first 32TB and then suddenly has serious issues. 030 * <br> 031 * Created by Tommy Ettinger on 5/8/2020. 032 */ 033public final class GoatRNG implements RandomnessSource, Serializable { 034 private static final long serialVersionUID = 1L; 035 /** 036 * Can be any long value. 037 */ 038 public long stateA; 039 /** 040 * Can be any long value. 041 */ 042 public long stateB; 043 044 /** 045 * Creates a new generator seeded using Math.random. 046 */ 047 public GoatRNG() { 048 this((long) ((Math.random() - 0.5) * 0x10000000000000L) 049 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L), 050 (long) ((Math.random() - 0.5) * 0x10000000000000L) 051 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L)); 052 } 053 054 public GoatRNG(long seed) { 055 stateA = (seed = (seed = ((seed = (((seed * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ seed >>> 27) * 0xAEF17502108EF2D9L) ^ seed >>> 25); 056 stateB = (seed = ((seed = (((seed * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ seed >>> 27) * 0xAEF17502108EF2D9L) ^ seed >>> 25; 057 } 058 059 public GoatRNG(final long seedA, final long seedB) { 060 stateA = seedA; 061 stateB = seedB; 062 } 063 064 /** 065 * Get the "A" part of the internal state as a long. 066 * 067 * @return the current internal state of this object. 068 */ 069 public long getStateA() { 070 return stateA; 071 } 072 073 /** 074 * Set the "A" part of the internal state with a long. 075 * 076 * @param stateA any 64-bit long 077 */ 078 public void setStateA(long stateA) { 079 this.stateA = stateA; 080 } 081 082 /** 083 * Get the "B" part of the internal state as a long. 084 * 085 * @return the current internal "B" state of this object. 086 */ 087 public long getStateB() { 088 return stateB; 089 } 090 091 /** 092 * Set the "B" part of the internal state with a long. 093 * 094 * @param stateB any 64-bit long 095 */ 096 public void setStateB(long stateB) { 097 this.stateB = stateB; 098 } 099 100 101 /** 102 * Using this method, any algorithm that might use the built-in Java Random 103 * can interface with this randomness source. 104 * 105 * @param bits the number of bits to be returned 106 * @return the integer containing the appropriate number of bits 107 */ 108 @Override 109 public final int next(final int bits) { 110 long s = (stateA += 0xD1342543DE82EF95L); 111 s ^= s >>> 31 ^ s >>> 23; 112 if(s < 0x46BC279692B5C323L) { 113 final long t = stateB; 114 s *= ((t ^ t << 9) | 1L); 115 return (int)(s ^ s >>> 25) >>> (32 - bits); 116 } 117 else { 118 final long t = (stateB += 0xB1E131D6149D9795L); 119 s *= ((t ^ t << 9) | 1L); 120 return (int)(s ^ s >>> 25) >>> (32 - bits); 121 } 122 } 123 /** 124 * Using this method, any algorithm that needs to efficiently generate more 125 * than 32 bits of random data can interface with this randomness source. 126 * <p> 127 * Get a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive). 128 * 129 * @return a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive) 130 */ 131 @Override 132 public final long nextLong() { 133 long s = (stateA += 0xD1342543DE82EF95L); 134 s ^= s >>> 31 ^ s >>> 23; 135 if(s < 0x46BC279692B5C323L) { 136 final long t = stateB; 137 s *= ((t ^ t << 9) | 1L); 138 return s ^ s >>> 25; 139 } 140 else { 141 final long t = (stateB += 0xB1E131D6149D9795L); 142 s *= ((t ^ t << 9) | 1L); 143 return s ^ s >>> 25; 144 } 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 need 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 GoatRNG copy() { 156 return new GoatRNG(stateA, stateB); 157 } 158 @Override 159 public String toString() { 160 return "GoatRNG with stateA 0x" + StringKit.hex(stateA) + "L and stateB 0x" + StringKit.hex(stateB) + 'L'; 161 } 162 163 @Override 164 public boolean equals(Object o) { 165 if (this == o) return true; 166 if (o == null || getClass() != o.getClass()) return false; 167 168 GoatRNG goatRNG = (GoatRNG) o; 169 170 return stateA == goatRNG.stateA && stateB == goatRNG.stateB; 171 } 172 173 @Override 174 public int hashCode() { 175 return (int) (31L * (stateA ^ (stateA >>> 32)) + (stateB ^ stateB >>> 32)); 176 } 177 178}