001package squidpony.squidmath; 002 003import squidpony.StringKit; 004 005import java.io.Serializable; 006 007/** 008 * A larger-period generator with 127 bits of state (two longs, one is always odd), a period of 2 to the 127, and what 009 * should be slightly better speed than the related OrbitRNG. It passes 32TB of PractRand testing with no anomalies or 010 * failures. The idea for this generator is to have a simple Weyl sequence (a counter with a large increment) for 011 * stateA, and at one point to multiply a value based on stateA by stateB, which is always odd. The trick is that stateB 012 * usually updates by adding a large even number, but about once every 10 billion generated numbers, decided by a 013 * comparison between a constant and stateA's value, it "shifts gears" and stays on the same value while stateA updates. 014 * <br> 015 * For some purposes you may want to instead consider {@link TangleRNG}, which also has two states (one odd) and uses a 016 * very similar algorithm, but it never "shifts gears," which drops its period down to 2 to the 64, makes it a 017 * {@link SkippingRandomness}, and should in theory speed it up (in practice, TangleRNG needs an extra step that actually 018 * makes it slower than GearRNG). An individual TangleRNG can't produce all possible long outputs and can produce some 019 * duplicates, but each pair of states for a TangleRNG has a different set of which outputs will be skipped and which 020 * will be duplicated. Since it would require months of solid number generation to exhaust the period of a TangleRNG, and 021 * that's the only time an output can be confirmed as skipped, it's probably fine for most usage to use many different 022 * TangleRNGs, all seeded differently. Other choices: you could use one {@link OrbitRNG} (which technically has a longer 023 * period, but some states produce very similar output), {@link DiverRNG} (if you don't mind that it never produces a 024 * duplicate output), {@link IsaacRNG} (if speed is less important but more secure output is), or Lathe64RNG, though all 025 * of those are probably slower than using one GearRNG object or even many TangleRNG objects. 026 * <br> 027 * The name comes from shifting gears; pretty straightforward here. 028 * <br> 029 * Created by Tommy Ettinger on 3/29/2020. 030 */ 031public final class GearRNG implements RandomnessSource, Serializable { 032 private static final long serialVersionUID = 5L; 033 /** 034 * Can be any long value. 035 */ 036 private long stateA; 037 /** 038 * Can be any odd long value. 039 */ 040 private long stateB; 041 042 /** 043 * Creates a new generator seeded using Math.random. 044 */ 045 public GearRNG() { 046 this((long) ((Math.random() - 0.5) * 0x10000000000000L) 047 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L), 048 (long) ((Math.random() - 0.5) * 0x10000000000000L) 049 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L)); 050 } 051 052 public GearRNG(long seed) { 053 stateA = (seed = ((seed = (((seed * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ seed >>> 27) * 0xAEF17502108EF2D9L) ^ seed >>> 25; 054 stateB = ((seed = ((seed = (((seed * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ seed >>> 27) * 0xAEF17502108EF2D9L) ^ seed >>> 25) | 1L; 055 } 056 057 public GearRNG(final long seedA, final long seedB) { 058 stateA = seedA; 059 stateB = seedB | 1L; 060 } 061 062 /** 063 * Get the "A" part of the internal state as a long. 064 * 065 * @return the current internal state of this object. 066 */ 067 public long getStateA() { 068 return stateA; 069 } 070 071 /** 072 * Set the "A" part of the internal state with a long. 073 * 074 * @param stateA any 64-bit long 075 */ 076 public void setStateA(long stateA) { 077 this.stateA = stateA; 078 } 079 080 /** 081 * Get the "B" part of the internal state as a long. 082 * 083 * @return the current internal "B" state of this object. 084 */ 085 public long getStateB() { 086 return stateB; 087 } 088 089 /** 090 * Set the "B" part of the internal state with a long; the lowest bit is always discarded and replaced with 1. 091 * That is, stateB is always an odd number, and if an even number is given it will be incremented. 092 * 093 * @param stateB any 64-bit long 094 */ 095 public void setStateB(long stateB) { 096 this.stateB = stateB | 1L; 097 } 098 099 100 /** 101 * Using this method, any algorithm that might use the built-in Java Random 102 * can interface with this randomness source. 103 * 104 * @param bits the number of bits to be returned 105 * @return the integer containing the appropriate number of bits 106 */ 107 @Override 108 public final int next(final int bits) { 109 final long s = (stateA += 0xC6BC279692B5C323L); 110 final long z = ((s < 0x800000006F17146DL) ? stateB : (stateB += 0x9479D2858AF899E6L)) * (s ^ s >>> 31); 111 return (int)(z ^ z >>> 25) >>> (32 - bits); 112 } 113 /** 114 * Using this method, any algorithm that needs to efficiently generate more 115 * than 32 bits of random data can interface with this randomness source. 116 * <p> 117 * Get a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive). 118 * 119 * @return a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive) 120 */ 121 @Override 122 public final long nextLong() { 123 final long s = (stateA += 0xC6BC279692B5C323L); 124 final long z = ((s < 0x800000006F17146DL) ? stateB : (stateB += 0x9479D2858AF899E6L)) * (s ^ s >>> 31); 125 return z ^ z >>> 25; 126 } 127 128 /** 129 * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the 130 * copy, both will generate the same sequence of random numbers from the point copy() was called. This just need to 131 * copy the state so it isn't shared, usually, and produce a new value with the same exact state. 132 * 133 * @return a copy of this RandomnessSource 134 */ 135 @Override 136 public GearRNG copy() { 137 return new GearRNG(stateA, stateB); 138 } 139 @Override 140 public String toString() { 141 return "GearRNG with stateA 0x" + StringKit.hex(stateA) + "L and stateB 0x" + StringKit.hex(stateB) + 'L'; 142 } 143 144 @Override 145 public boolean equals(Object o) { 146 if (this == o) return true; 147 if (o == null || getClass() != o.getClass()) return false; 148 149 GearRNG gearRNG = (GearRNG) o; 150 151 return stateA == gearRNG.stateA && stateB == gearRNG.stateB; 152 } 153 154 @Override 155 public int hashCode() { 156 return (int) (31L * (stateA ^ (stateA >>> 32)) + (stateB ^ stateB >>> 32)); 157 } 158 159}