001package squidpony.squidmath; 002 003import squidpony.StringKit; 004 005import java.io.Serializable; 006 007/** 008 * A RandomnessSource based on PCG-Random that has a single int of state. Its period is extremely short at 2 to the 32, 009 * but its quality over that period is high even though its speed is not especially noteworthy. This generator is not 010 * suitable for GWT; for that you should use {@link Starfish32RNG} or its wrapper {@link GWTRNG} if you need a 011 * StatefulRandomness, {@link Lathe32RNG} if you want optimal speed and don't mind distribution flaws when producing 012 * longs, or {@link Oriole32RNG} or {@link XoshiroStarPhi32RNG} if you need a higher period but don't need 013 * StatefulRandomness' state adjustment methods. 014 * <br> 015 * Quality should be excellent in this version (at least for a generator with so little state) since it's based directly 016 * on PCG-Random's choices of numerical constants. Visual tests, at least, appear indistinguishable from other PRNGs. 017 * Period is very low, at 2 to the 32, but all seeds should be valid, including 0. Generating 64 bits of random data 018 * takes a little less than twice as much time as generating 32 bits, since this can avoid some overhead via inlining. 019 * <br> 020 * The name can be construed as Pint-Size, since this has a small period and uses a smaller amount of space, or as 021 * Permuted Int, since this is based on PermutedRNG, changed to use 32-bit operations on ints. 022 * <br> 023 * Based on work by Melissa E. O'Neill for PCG-Random; some code has been ported more-directly than other sections, but 024 * the foundation for this class would not be possible without O'Neill's work. 025 * <br> 026 * Created by Tommy Ettinger on 11/15/2016. 027 */ 028public final class PintRNG implements RandomnessSource, StatefulRandomness, Serializable { 029 030 /** 2 raised to the 53, - 1. */ 031 private static final long DOUBLE_MASK = ( 1L << 53 ) - 1; 032 /** 2 raised to the -53. */ 033 private static final double NORM_53 = 1. / ( 1L << 53 ); 034 /** 2 raised to the 24, -1. */ 035 private static final long FLOAT_MASK = ( 1L << 24 ) - 1; 036 /** 2 raised to the -24. */ 037 private static final double NORM_24 = 1. / ( 1L << 24 ); 038 039 private static final long serialVersionUID = -374415589203474497L; 040 041 public int state; /* The state can be seeded with any value. */ 042 043 /** Creates a new generator seeded using Math.random. */ 044 public PintRNG() { 045 this((int)((Math.random() - 0.5) * 4.294967296E9)); 046 } 047 048 public PintRNG( final long seed ) { 049 setState(seed); 050 } 051 052 public PintRNG(final int a) 053 { 054 state = a; 055 } 056 057 @Override 058 public int next( int bits ) 059 { 060 int p = (state = state * 0x2C9277B5 + 0xAC564B05); 061 p ^= p >>> (4 + (p >>> 28)); 062 return (((p *= 0x108EF2D9) >>> 22) ^ p) >>> (32 - bits); 063 } 064 065 /** 066 * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer. 067 * @return any int, all 32 bits are random 068 */ 069 public int nextInt() { 070 // increment = 2891336453; 071 // multiplier = 747796405; 072 073// int p = state; 074// p ^= p >>> (4 + (p >>> 28)); 075// state = state * 0x2C9277B5 + 0xAC564B05; 076 int p = (state = state * 0x2C9277B5 + 0xAC564B05); 077 p ^= p >>> (4 + (p >>> 28)); 078 return ((p *= 0x108EF2D9) >>> 22) ^ p; 079 } 080 081 /** 082 * Can return any long, positive or negative, of any size permissible in a 64-bit signed integer. 083 * Internally, generates two random 32-bit values and combines them into one random long. 084 * @return any long, all 64 bits are random 085 */ 086 @Override 087 public long nextLong() { 088 int p = (state = state * 0x2C9277B5 + 0xAC564B05); 089 p ^= p >>> (4 + (p >>> 28)); 090 int q = (state = state * 0x2C9277B5 + 0xAC564B05); 091 q ^= q >>> (4 + (q >>> 28)); 092 return (((p *= 0x108EF2D9) >>> 22) ^ p) | ((((q *= 0x108EF2D9) >>> 22) ^ q) & 0xffffffffL) << 32; 093 } 094 095 /** 096 * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the 097 * copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to 098 * copy the state so it isn't shared, usually, and produce a new value with the same exact state. 099 * 100 * @return a copy of this RandomnessSource 101 */ 102 @Override 103 public PintRNG copy() { 104 return new PintRNG(state); 105 } 106 107 /** 108 * Exclusive on the upper bound. The lower bound is 0. 109 * <br> 110 * Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 111 * @param bound the upper bound; should be positive 112 * @return a random int less than n and at least equal to 0 113 */ 114 public int nextInt( final int bound ) { 115 return (bound <= 0) ? 0 : (int)((bound * (nextInt() & 0x7FFFFFFFL)) >> 31); 116 } 117 /** 118 * Inclusive lower, exclusive upper. 119 * @param lower the lower bound, inclusive, can be positive or negative 120 * @param upper the upper bound, exclusive, should be positive, must be greater than lower 121 * @return a random int at least equal to lower and less than upper 122 */ 123 public int nextInt( final int lower, final int upper ) { 124 if ( upper - lower <= 0 ) throw new IllegalArgumentException("Upper bound must be greater than lower bound"); 125 return lower + nextInt(upper - lower); 126 } 127 128 /** 129 * Gets a uniform random double in the range [0.0,1.0) 130 * @return a random double at least equal to 0.0 and less than 1.0 131 */ 132 public double nextDouble() { 133 return ( nextLong() & DOUBLE_MASK ) * NORM_53; 134 } 135 136 /** 137 * Gets a uniform random double in the range [0.0,outer) given a positive parameter outer. If outer 138 * is negative, it will be the (exclusive) lower bound and 0.0 will be the (inclusive) upper bound. 139 * @param outer the exclusive outer bound, can be negative 140 * @return a random double between 0.0 (inclusive) and outer (exclusive) 141 */ 142 public double nextDouble(final double outer) { 143 return nextDouble() * outer; 144 } 145 146 /** 147 * Gets a uniform random float in the range [0.0,1.0) 148 * @return a random float at least equal to 0.0 and less than 1.0 149 */ 150 public float nextFloat() { 151 return (float)( ( nextInt() & FLOAT_MASK ) * NORM_24 ); 152 } 153 154 /** 155 * Gets a random value, true or false. 156 * Calls nextInt() once. 157 * @return a random true or false value. 158 */ 159 public boolean nextBoolean() { 160 return nextInt() > 0; 161 } 162 163 /** 164 * Given a byte array as a parameter, this will fill the array with random bytes (modifying it 165 * in-place). Calls nextInt() {@code Math.ceil(bytes.length / 4.0)} times. 166 * @param bytes a byte array that will have its contents overwritten with random bytes. 167 */ 168 public void nextBytes( final byte[] bytes ) { 169 int i = bytes.length, n; 170 while( i != 0 ) { 171 n = Math.min( i, 4 ); 172 for ( int bits = nextInt(); n-- != 0; bits >>>= 8 ) bytes[ --i ] = (byte)bits; 173 } 174 } 175 176 177 178 /** 179 * Sets the current state of this generator (an int) using only the least-significant 32 bits of seed (by casting 180 * a mask of those bits in seed to int, which helps ensure that a full 32 bits of state are possible). Giving 181 * int seeds should set the seed to an identical int; long seeds will lose any information in higher bits (including 182 * the sign, so 0xFFFFFFFF00000000L, which is a negative long, would be treated as 0 since only the 0x00000000 part 183 * at the end is actually used). 184 * @param seed the seed to use for this PintRNG, as if it was constructed with this seed. 185 */ 186 @Override 187 public void setState( final long seed ) { 188 state = (int)(seed & 0xFFFFFFFFL); 189 } 190 /** 191 * Gets the current state of this generator. 192 * @return the current seed of this PintRNG, changed once per call to nextInt() 193 */ 194 @Override 195 public long getState() { 196 return state; 197 } 198 199 @Override 200 public String toString() { 201 return "PintRNG with state 0x" + StringKit.hex(state); 202 } 203 204 @Override 205 public boolean equals(Object o) { 206 if (this == o) return true; 207 if (o == null || getClass() != o.getClass()) return false; 208 209 PintRNG pintRNG = (PintRNG) o; 210 211 return state == pintRNG.state; 212 213 } 214 215 @Override 216 public int hashCode() { 217 return state; 218 } 219 /** 220 * Advances or rolls back the PintRNG's state without actually generating each number. Skip forward 221 * or backward a number of steps specified by advance, where a step is equal to one call to nextInt(), 222 * and returns the random number produced at that step (you can get the state with {@link #getState()}). 223 * <br> 224 * The method used here is based on Brown, "Random Number Generation with Arbitrary Stride,", Transactions of the 225 * American Nuclear Society (Nov. 1994). The code is mostly the same as in PCG-Random's C port by M.E. O'Neill, 226 * specifically <a href="https://github.com/imneme/pcg-c/blob/master/src/pcg-advance-32.c">this file</a>. Skipping 227 * ahead or behind takes more than constant time, unlike with {@link LightRNG}, but less time than calling nextInt() 228 * {@code advance} times. Skipping backwards by one step is the worst case for this. 229 * @param advance Number of future generations to skip past. Can be negative to backtrack. 230 * @return the int that would be generated after generating advance random numbers. 231 */ 232 public int skip(int advance) 233 { 234 int acc_mult = 1; 235 int acc_plus = 0; 236 int cur_mult = 0x2C9277B5; 237 int cur_plus = 0xAC564B05; 238 while (advance != 0) { 239 if ((advance & 1) == 1) { 240 acc_mult *= cur_mult; 241 acc_plus = acc_plus * cur_mult + cur_plus; 242 } 243 cur_plus *= (cur_mult + 1); 244 cur_mult *= cur_mult; 245 advance >>>= 1; 246 } 247 int p = (state = acc_mult * state + acc_plus); 248 p ^= p >>> (4 + (p >>> 28)); 249 return ((p *= 0x108EF2D9) >>> 22) ^ p; 250 } 251 252 /** 253 * Gets a pseudo-random int that is a permutation of {@code state}, which is an int. 254 * This should normally be called with a technique like 255 * {@code PintRNG.determine(state = state * 0x2C9277B5 + 0xAC564B05)}, where 0xAC564B05 can be changed to any odd 256 * constant as long as it is the same across calls to this. You can effectively produce multiple uncorrelated 257 * streams by adding different constants in place of 0xAC564B05, applied to different states. 258 * @param state any int, but should be updated like {@code state = state * 0x2C9277B5 + 0xAC564B05}, where 0xAC564B05 can be any odd-number constant 259 * @return any int, pseudo-randomly obtained from state 260 */ 261 public static int determine(int state) 262 { 263 state ^= state >>> (4 + (state >>> 28)); 264 return ((state *= 0x108EF2D9) >>> 22) ^ state; 265 } 266 /** 267 * Like {@link #determine(int)}, gets a pseudo-random int that is a permutation of {@code state}, which is an int. 268 * Unlike determine(), this static method performs an extra step to avoid correlation between similar inputs, such 269 * as 4, 5, and 6, and their outputs. If you already give very distant numbers as subsequent inputs to determine(), 270 * then you should continue to use that method unless you discover issues with correlation; otherwise it's not a bad 271 * idea to default to this method, though it is somewhat slower than determine(). This method is safe to use with 272 * sequential ints, so you can call it with the technique {@code PintRNG.disperse(++state)}, or just use it on int 273 * data as you obtain it to randomize its values. 274 * @param state any int 275 * @return any int, pseudo-randomly obtained from state 276 */ 277 public static int disperse(int state) 278 { 279 state = ((state >>> 19 | state << 13) ^ 0x13A5BA1D); 280 state ^= state >>> (4 + (state >>> 28)); 281 return ((state *= 0x108EF2D9) >>> 22) ^ state; 282 } 283 public static int determine(final int a, final int b) 284 { 285 int state = a * 0x9E3779B9 + b * 0x85157AF5; 286 state ^= state >>> (4 + (state >>> 28)); 287 return ((state *= 0x108EF2D9) >>> 22) ^ state; 288 } 289 290 public static int determineBounded(int state, final int bound) 291 { 292 state ^= state >>> (4 + (state >>> 28)); 293 return (int)((bound * ((((state *= 0x108EF2D9) >>> 22) ^ state) & 0x7FFFFFFFL)) >>> 31); 294 } 295 public static int disperseBounded(int state, final int bound) 296 { 297 state = ((state >>> 19 | state << 13) ^ 0x13A5BA1D); 298 state ^= state >>> (4 + (state >>> 28)); 299 return (int)((bound * ((((state *= 0x108EF2D9) >>> 22) ^ state) & 0x7FFFFFFFL)) >>> 31); 300 } 301 302}