001package squidpony.squidmath; 002 003import java.io.Serializable; 004 005/** 006 * An implementation of {@link IRNG} that allows specifying a distribution for all random numbers it produces via a 007 * {@link squidpony.squidmath.IDistribution.SimpleDistribution} value. You can adapt any IDistribution to a 008 * SimpleDistribution with the static methods in SimpleDistribution, like 009 * {@link squidpony.squidmath.IDistribution.SimpleDistribution#fractionalDistribution(IDistribution)}. If no 010 * distribution is specified, this uses {@link CurvedBoundedDistribution#instance}. 011 * <br> 012 * This uses a {@link MoonwalkRNG} internally to handle the number generation that the distribution requests. While you 013 * can call methods on {@link #rng} that are specific to MoonwalkRNG, many distributions will get multiple random 014 * numbers where a normal RNG would only get one, and this makes the state-jumping features of MoonwalkRNG less useful 015 * here. It's still a fast generator when it comes to generating doubles, which is why it's used here; GWT-oriented 016 * generators would be slower at generating doubles on desktop and many mobile platforms. 017 * <br> 018 * Created by Tommy Ettinger on 11/27/2019. 019 */ 020public class DistributedRNG extends AbstractRNG implements IStatefulRNG, StatefulRandomness, Serializable { 021 022 private static final long serialVersionUID = 1L; 023 public IDistribution.SimpleDistribution distribution; 024 public MoonwalkRNG rng; 025 026 public DistributedRNG() 027 { 028 this((long) ((Math.random() - 0.5) * 0x10000000000000L) 029 ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L)); 030 } 031 public DistributedRNG(long state) 032 { 033 this(state, CurvedBoundedDistribution.instance); 034 } 035 public DistributedRNG(long state, IDistribution.SimpleDistribution distribution) 036 { 037 this.rng = new MoonwalkRNG(state); 038 this.distribution = distribution; 039 } 040 /** 041 * Get up to 32 bits (inclusive) of random output; the int this produces 042 * will not require more than {@code bits} bits to represent. 043 * 044 * @param bits an int between 1 and 32, both inclusive 045 * @return a random number that fits in the specified number of bits 046 */ 047 @Override 048 public final int next( int bits ) { 049 return (int) (distribution.nextDouble(rng) * (1 << bits)); 050 } 051 052 /** 053 * Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive). 054 * 055 * @return a 32-bit random int. 056 */ 057 @Override 058 public int nextInt() { 059 return (int) (distribution.nextDouble(rng) * 0x1p32 - 0x1p31); 060 } 061 062 /** 063 * Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive). This implementation has "holes" in 064 * its range, numbers that it cannot produce regardless of distribution. 065 * 066 * @return a 64-bit random long. 067 */ 068 @Override 069 public long nextLong() { 070 return (long) (distribution.nextDouble(rng) * 0x1p64 - 0x1p63); 071 } 072 073 /** 074 * Get a random bit of state, interpreted as true or false with approximately equal likelihood. 075 * 076 * @return a random boolean. 077 */ 078 @Override 079 public boolean nextBoolean() { 080 return distribution.nextDouble(rng) < 0.5; 081 } 082 083 /** 084 * Gets a random double between 0.0 inclusive and 1.0 exclusive. 085 * This returns a maximum of 0.9999999999999999 because that is the largest double value that is less than 1.0 . 086 * 087 * @return a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive) 088 */ 089 @Override 090 public double nextDouble() { 091 return distribution.nextDouble(rng); 092 } 093 094 /** 095 * Gets a random float between 0.0f inclusive and 1.0f exclusive. 096 * This returns a maximum of 0.99999994 because that is the largest float value that is less than 1.0f . 097 * 098 * @return a float between 0f (inclusive) and 0.99999994f (inclusive) 099 */ 100 @Override 101 public float nextFloat() { 102 return (float) distribution.nextDouble(rng); 103 } 104 /** 105 * Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or 106 * negative. 107 * 108 * @param bound the upper bound (exclusive) 109 * @return the found number 110 */ 111 @Override 112 public int nextInt(int bound) { 113 return (int) (distribution.nextDouble(rng) * bound) & ~(bound >> 31); 114 } 115 116 /** 117 * Exclusive on bound (which must be positive), with an inner bound of 0. 118 * If bound is negative or 0 this always returns 0. 119 * 120 * @param bound the outer exclusive bound; should be positive, otherwise this always returns 0L 121 * @return a random long between 0 (inclusive) and bound (exclusive) 122 */ 123 @Override 124 public long nextLong(long bound) { 125 return (long) (distribution.nextDouble(rng) * bound) & ~(bound >> 63); 126 } 127 128 /** 129 * Exclusive on bound (which may be positive or negative), with an inner bound of 0. 130 * If bound is negative this returns a negative long; if bound is positive this returns a positive long. The bound 131 * can even be 0, which will cause this to return 0L every time. 132 * 133 * @param bound the outer exclusive bound; can be positive or negative 134 * @return a random long between 0 (inclusive) and bound (exclusive) 135 */ 136 @Override 137 public long nextSignedLong(long bound) { 138 return (long) (distribution.nextDouble(rng) * bound); 139 } 140 141 /** 142 * Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), 143 * or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result. 144 * 145 * @param bound the outer bound (exclusive), can be negative or positive 146 * @return the found number 147 */ 148 @Override 149 public int nextSignedInt(int bound) { 150 return (int) (distribution.nextDouble(rng) * bound); 151 } 152 153 /** 154 * Creates a copy of this IRNG; it will generate the same random numbers, given the same calls in order, as this 155 * IRNG at the point copy() is called. The copy will not share references with this IRNG, except to 156 * {@link #distribution}, which usually shouldn't change much. 157 * 158 * @return a copy of this IRNG 159 */ 160 @Override 161 public DistributedRNG copy() { 162 return new DistributedRNG(rng.getState(), distribution); 163 } 164 165 /** 166 * Gets a view of this IRNG in a way that implements {@link Serializable}, which may simply be this IRNG if it 167 * implements Serializable as well as IRNG. 168 * 169 * @return a {@link Serializable} view of this IRNG or a similar one; may be {@code this} 170 */ 171 @Override 172 public Serializable toSerializable() { 173 return this; 174 } 175 176 /** 177 * Get the current internal state of the StatefulRandomness as a long. 178 * 179 * @return the current internal state of this object. 180 */ 181 @Override 182 public long getState() { 183 return rng.getState(); 184 } 185 186 /** 187 * Set the current internal state of this StatefulRandomness with a long; this accepts a state of 0 with no issues. 188 * 189 * @param state a 64-bit long. 190 */ 191 @Override 192 public void setState(long state) { 193 rng.setState(state); 194 } 195}