com.github.tommyettinger.random.LaserRandom Maven / Gradle / Ivy
Show all versions of juniper Show documentation
/*
* Copyright (c) 2022-2023 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.github.tommyettinger.random;
import java.util.Random;
/**
* A faster and much-higher-quality substitute for {@link Random}. This allows many different random number
* streams that don't overlap, and offers a more substantial API for commonly-used functions. This is not a
* cryptographic random number generator, and should not be used in place of one.
*
* This fills in much of the functionality of MathUtils in libGDX, though with all code as instance methods
* instead of static methods, and some things renamed (randomTriangular() became {@link #nextTriangular()},
* for instance, and random() became {@link #nextFloat()}). It also supplies some rare and sometimes-useful
* code: {@link #skip(long)} allows "fast-forward" and "rewind" along with {@link #previousLong()} to simply
* go back one step, you can get and set the exact state with {@link #getStateA()}, {@link #getStateB()},
* {@link #setStateA(long)}, {@link #setStateB(long)}, and {@link #setState(long, long)} (which is useful
* if you want to save a LaserRandom and reload it later), and there's bounded int and long generators which
* can use a negative number for their exclusive outer bound ({@link #nextSignedInt(int)} and
* {@link #nextSignedLong(long)}, plus overloads that take an inner bound). There's float and double
* generators that are inclusive on both ends ({@link #nextInclusiveFloat()}, and
* {@link #nextInclusiveDouble()}. There's {@link #nextGaussian()}, which is implemented differently from
* java.util.Random and always advances the state once. This implements all optional methods in
* EnhancedRandom, and implements almost all EnhancedRandom methods explicitly, which allows LaserRandom to
* be copied more easily without depending on juniper (see below).
*
* Every method defined in this class advances the state by the same amount unless otherwise documented (only
* {@link #nextTriangular()} and {@link #nextTriangular(float)} advance the state twice). The state can
* advance 2 to the 64 times before the sequence of random numbers repeats, which would take a few years of
* continuous generation. There are also 2 to the 63 possible sequences this can produce; you can tell which
* one you're using with {@link #getStream()}. Note, {@link Random} can only advance 2 to the 48 times, which
* takes under half a day to make it repeat on recent laptop hardware while also analyzing the numbers for
* statistical issues. This generator is more comparable to SplittableRandom, introduced in JDK 8 but not
* available in Android (even with desugaring) or GWT currently. SplittableRandom also can produce 2 to the
* 64 numbers before repeating the sequence, and also has 2 to the 63 streams, but it will always produce
* each possible long value exactly once over the course of that sequence. Each of LaserRandom's streams
* produces a different sequence of numbers with a different set of numbers it omits and a different set of
* numbers it produces more than once; each of SplittableRandom's streams simply rearranges the order of all
* possible longs. Though it might seem like an issue that a LaserRandom stream has gaps in its possible
* output, if you appended all 2 to the 63 possible LaserRandom streams in full, the gargantuan result would
* include all longs equally often. So, if the stream is selected effectively at random, then the subset of
* that stream that actually gets used should be fair (and it's very unlikely that any usage will need a full
* stream of over 18 quintillion pseudo-random longs). It is strongly recommended that you use very different
* numbers when creating many LaserRandom objects with similar states, because there is a noticeable
* correlation between, for instance, a grid of LaserRandom objects initialized with stateA drawn from the
* odd numbers 1 through 101, and stateB drawn from another odd number 1 through 101. Using
* {@link #setSeed(long)} essentially eliminates this risk, so it's a good idea to seed this with one long.
*
* If statistical quality is a concern, don't use {@link Random}, since the aforementioned
* analysis finds statistical failures in about a minute when checking about 16GB of output; this class can
* produce 64TB of random output without a tool like PractRand finding any failures (sometimes it can't find
* any minor anomaly over several days of testing). RandomXS128 has some flaws, though they are not nearly as
* severe as Random's; mostly they are limited to a particular kind of failure affecting the least
* significant bits (the technical name for the test it fails is a "binary matrix rank" test, which a wide
* variety of related generators can fail if they don't adequately randomize their outputs). RandomXS128's
* flaws would be permissible if it was faster than any competitors, but it isn't, and there have been two
* improved relatives of its algorithm published since it was created. Both of these improvements,
* xoroshiro128** and xoshiro256**, are slower when implemented in Java than LaserRandom (also when all are
* implemented in C and compiled with GCC or Clang, typically). There are also some concerns about specific
* failure cases when the output of xoroshiro128** or xoshiro256** is multiplied by any of quadrillions of
* constants and tested after that multiplication (see M.E. O'Neill's dissection of xoshiro256**
* here). Xoshiro256**, like
* LaserRandom, can't be reliably initialized using nearby values for its state variables, and does much
* better if you use its setSeed(long) method. We do implement Xoshiro256** here, because it provides
* 4-dimensional equidistribution, and that is hard to find.
*
* You can copy this class independently of the library it's part of; it's meant as a general replacement for
* Random and also RandomXS128. LaserRandom is generally faster than RandomXS128, and can be over 3x faster
* when running on OpenJ9 (generating over 3 billion random long values per second). If you copy this, the
* only step you probably need to do is to remove {@code extends EnhancedRandom} from the class, since
* almost all of EnhancedRandom consists of either parent methods that this overrides explicitly, or to
* provide a common interface for pseudo-random number generators on the JVM. This class avoids using the
* Override annotation specifically because copying the class and removing the EnhancedRandom implementation
* would cause compile errors if Override annotations were present. If you do keep this class implementing
* EnhancedRandom, then that permits some extra methods to come in via default implementations, like
* nextExclusiveFloat() (which uses the BitConversion class here from digital), minIntOf(), maxLongOf(), etc.
*
* You may want to compare this class with TricycleRandom and FourWheelRandom in the same package; both of
* those have a larger state size (and should usually have a larger period), are usually faster, and also
* implement all of EnhancedRandom (except for {@link #skip(long)}), but they do even less randomizing for
* the first result they return, so if the seeding has a pattern, then the start of their sequences will
* have patterns. These patterns are less obvious but do persist in LaserRandom, and don't persist in
* TricycleRandom or FourWheelRandom over a long run. All generators here do well when using
* {@link #setSeed(long)} to set the full state.
*
* Pew pew! Lasers!
*
* @author Tommy Ettinger
*/
public class LaserRandom extends EnhancedRandom {
/**
* Can be any long value.
*/
protected long stateA;
/**
* Must be odd.
*/
protected long stateB;
/**
* Creates a new LaserRandom. This constructor sets the states of the
* random number generator to values very likely to be distinct from
* any other invocation of this constructor.
*/
public LaserRandom () {
super();
stateA = (long)((Math.random() - 0.5) * 0x1p52) ^ (long)((Math.random() - 0.5) * 0x1p64);
stateB = (long)((Math.random() - 0.5) * 0x1p52) ^ (long)((Math.random() - 0.5) * 0x1p64) | 1L;
}
/**
* Creates a new LaserRandom using a single {@code long} seed; the stream depends on whether the seed is even or odd.
*
* @param seed the initial seed
* @see #setSeed(long)
*/
public LaserRandom (long seed) {
super(seed);
stateA = seed;
stateB = seed | 1L;
}
/**
* Creates a new LaserRandom using {@code seedA} exactly to set stateA (as with {@link #setStateA(long)},,
* and using {@code seedB} to set stateB as with {@link #setStateB(long)} (meaning seedB will be used exactly if odd,
* otherwise it will have 1 added to it and then used).
*
* @param seedA any long; will be used exactly to set stateA as with {@link #setStateA(long)}
* @param seedB any odd long will be used exactly to set stateB, otherwise, as with {@link #setStateB(long)}, it will be made odd
*/
public LaserRandom (final long seedA, final long seedB) {
super(seedA);
stateA = seedA;
stateB = seedB | 1L;
}
@Override
public String getTag() {
return "LasR";
}
/**
* LaserRandom has two possible states, both {@code long}.
* The second state (selection {@code 1}) is always an odd number, and if
* anything tries to set an even number to that state, the actual state used
* will be one greater.
*
* @return 2 (two)
*/
public int getStateCount () {
return 2;
}
/**
* Get the "A" part of the internal state as a long.
*
* @return the current internal "A" state of this object.
*/
public long getStateA () {
return stateA;
}
/**
* Set the "A" part of the internal state with a long.
*
* @param stateA a 64-bit long
*/
public void setStateA (long stateA) {
this.stateA = stateA;
}
/**
* Get the "B" part of the internal state as a long.
*
* @return the current internal "B" state of this object.
*/
public long getStateB () {
return stateB;
}
/**
* Set the "B" part of the internal state with a long; the least significant bit is ignored (will always be odd).
* That is, if stateB is odd, this uses it verbatim; if stateB is even, it adds 1 to it to make it odd.
*
* @param stateB a 64-bit long; the lowest bit will be ignored and the result always used as an odd number
*/
public void setStateB (long stateB) {
this.stateB = stateB | 1L;
}
/**
* Sets both parts of the internal state with one call; {@code stateA} is used verbatim, but {@code stateB} has
* its least significant bit ignored and always overwritten with a '1' bit (meaning stateB will always be odd).
* You can use any long for stateA without it being changed, and can use any odd long for stateB without it
* being changed; as such, keeping {@code stateB} an odd number should be optimal.
*
* @param stateA a 64-bit long
* @param stateB a 64-bit long; the lowest bit will be ignored and the result always used as an odd number
*/
public void setState (long stateA, long stateB) {
this.stateA = stateA;
this.stateB = stateB | 1L;
}
/**
* Gets a selected state value from this LaserRandom. If selection is an even number,
* this returns stateA, and if selection is odd, it returns stateB. This returns the
* exact value of the selected state.
*
* @param selection used to select which state variable to get (usually 0 or 1)
* @return the exact value of the selected state
*/
public long getSelectedState (int selection) {
return (selection & 1) == 0 ? stateA : stateB;
}
/**
* Sets a selected state value to the given long {@code value}. If selection is an even
* number, this sets stateA to value as-is, and if selection is odd, this sets stateB to
* value made odd (that is, if value is even, it uses value + 1, otherwise it uses value).
*
* @param selection used to select which state variable to set (usually 0 or 1)
* @param value the exact value to use for the selected state, if valid
*/
public void setSelectedState (int selection, long value) {
if ((selection & 1) == 0)
stateA = value;
else
stateB = value | 1L;
}
/**
* Sets the seed of this random number generator using a single
* {@code long} seed. The general contract of {@code setSeed} is
* that it alters the state of this random number generator object
* so as to be in exactly the same state as if it had just been
* created with the argument {@code seed} as a seed.
*
* The implementation of {@code setSeed} by class
* {@code LaserRandom} uses all 64 bits of the given seed for
* {@link #setStateA(long)}, and all but the least-significant bit
* of the seed for {@link #setStateB(long)} (the omitted bit is
* always set to 1 in stateB, meaning stateB is always odd).
*
* @param seed the initial seed
*/
public void setSeed (long seed) {
stateB = (stateA = seed) | 1L;
}
/**
* Generates the next pseudorandom number with a specific maximum size in bits (not a max number).
* If you want to get a random number in a range, you should usually use {@link #nextInt(int)} instead.
* For some specific cases, this method is more efficient and less biased than {@link #nextInt(int)}.
* For {@code bits} values between 1 and 30, this should be similar in effect to
* {@code nextInt(1 << bits)}; though it won't typically produce the same values, they will have
* the correct range. If {@code bits} is 31, this can return any non-negative {@code int}; note that
* {@code nextInt(1 << 31)} won't behave this way because {@code 1 << 31} is negative. If
* {@code bits} is 32 (or 0), this can return any {@code int}.
*
*
The general contract of {@code next} is that it returns an
* {@code int} value and if the argument {@code bits} is between
* {@code 1} and {@code 32} (inclusive), then that many low-order
* bits of the returned value will be (approximately) independently
* chosen bit values, each of which is (approximately) equally
* likely to be {@code 0} or {@code 1}.
*
*
* @param bits the amount of random bits to request, from 1 to 32
* @return the next pseudorandom value from this random number
* generator's sequence
*/
public int next (int bits) {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return (int)(z ^ z >>> 26 ^ z >>> 6) >>> 32 - bits;
}
/**
* Generates random bytes and places them into a user-supplied
* byte array. The number of random bytes produced is equal to
* the length of the byte array.
*
* @param bytes the byte array to fill with random bytes
* @throws NullPointerException if the byte array is null
*/
public void nextBytes (byte[] bytes) {
for (int i = 0; i < bytes.length; ) {for (long r = nextLong(), n = Math.min(bytes.length - i, 8); n-- > 0; r >>>= 8) {bytes[i++] = (byte)r;}}
}
/**
* Returns the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence. The general
* contract of {@code nextInt} is that one {@code int} value is
* pseudorandomly generated and returned. All 232 possible
* {@code int} values are produced with (approximately) equal probability.
*
* @return the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence
*/
public int nextInt () {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return (int)(z ^ z >>> 26 ^ z >>> 6);
}
/**
* Returns a pseudorandom, uniformly distributed {@code int} value
* between 0 (inclusive) and the specified value (exclusive), drawn from
* this random number generator's sequence. The general contract of
* {@code nextInt} is that one {@code int} value in the specified range
* is pseudorandomly generated and returned. All {@code bound} possible
* {@code int} values are produced with (approximately) equal
* probability.
*
* It should be mentioned that the technique this uses has some bias, depending
* on {@code bound}, but it typically isn't measurable without specifically looking
* for it. Using the method this does allows this method to always advance the state
* by one step, instead of a varying and unpredictable amount with the more typical
* ways of rejection-sampling random numbers and only using numbers that can produce
* an int within the bound without bias.
* See M.E. O'Neill's
* blog about random numbers for discussion of alternative, unbiased methods.
*
* @param bound the upper bound (exclusive). If negative or 0, this always returns 0.
* @return the next pseudorandom, uniformly distributed {@code int}
* value between zero (inclusive) and {@code bound} (exclusive)
* from this random number generator's sequence
*/
public int nextInt (int bound) {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return (int)(bound * ((z ^ z >>> 26 ^ z >>> 6) & 0xFFFFFFFFL) >> 32) & ~(bound >> 31);
}
/**
* Returns a pseudorandom, uniformly distributed {@code int} value
* between 0 (inclusive) and the specified value (exclusive), drawn from
* this random number generator's sequence. The general contract of
* {@code nextInt} is that one {@code int} value in the specified range
* is pseudorandomly generated and returned. All {@code bound} possible
* {@code int} values are produced with (approximately) equal
* probability.
*
* This method treats the outer bound as unsigned, so if a negative int is passed as
* {@code bound}, it will be treated as positive and larger than {@link Integer#MAX_VALUE}.
* That means this can produce results that are positive or negative, but when you
* mask the result and the bound with {@code 0xFFFFFFFFL} (to treat them as unsigned),
* the result will always be between {@code 0L} (inclusive) and the masked bound
* (exclusive).
*
* It should be mentioned that the technique this uses has some bias, depending
* on {@code bound}, but it typically isn't measurable without specifically looking
* for it. Using this technique allows this method to always advance the state
* by one step, instead of a varying and unpredictable amount with the more typical
* ways of rejection-sampling random numbers and only using numbers that can produce
* an int within the bound without bias.
* See M.E. O'Neill's
* blog about random numbers for discussion of alternative, unbiased methods.
*
* @param bound the upper bound (exclusive). If negative or 0, this always returns 0.
* @return the next pseudorandom, uniformly distributed {@code int}
* value between zero (inclusive) and {@code bound} (exclusive)
* from this random number generator's sequence
*/
public int nextUnsignedInt (int bound) {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return (int)((bound & 0xFFFFFFFFL) * ((z ^ z >>> 26 ^ z >>> 6) & 0xFFFFFFFFL) >>> 32);
}
/**
* Returns a pseudorandom, uniformly distributed {@code int} value between an
* inner bound of 0 (inclusive) and the specified {@code outerBound} (exclusive).
* This is meant for cases where the outer bound may be negative, especially if
* the bound is unknown or may be user-specified. A negative outer bound is used
* as the lower bound; a positive outer bound is used as the upper bound. An outer
* bound of -1, 0, or 1 will always return 0, keeping the bound exclusive (except
* for outer bound 0). This method is slightly slower than {@link #nextInt(int)}.
*
* @param outerBound the outer exclusive bound; may be any int value, allowing negative
* @return a pseudorandom int between 0 (inclusive) and outerBound (exclusive)
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public int nextSignedInt (int outerBound) {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
outerBound = (int)(outerBound * ((z ^ z >>> 26 ^ z >>> 6) & 0xFFFFFFFFL) >> 32);
return outerBound + (outerBound >>> 31);
}
/**
* Returns a pseudorandom, uniformly distributed {@code int} value between the
* specified {@code innerBound} (inclusive) and the specified {@code outerBound}
* (exclusive). If {@code outerBound} is less than or equal to {@code innerBound},
* this always returns {@code innerBound}.
*
*
For any case where outerBound might be valid but less than innerBound, you
* can use {@link #nextSignedInt(int, int)}.
*
* @param innerBound the inclusive inner bound; may be any int, allowing negative
* @param outerBound the exclusive outer bound; must be greater than innerBound (otherwise this returns innerBound)
* @return a pseudorandom int between innerBound (inclusive) and outerBound (exclusive)
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public int nextInt (int innerBound, int outerBound) {
return (int)(innerBound + (nextUnsignedInt(outerBound - innerBound) & ~((long)outerBound - (long)innerBound >> 63)));
}
/**
* Returns a pseudorandom, uniformly distributed {@code int} value between the
* specified {@code innerBound} (inclusive) and the specified {@code outerBound}
* (exclusive). This is meant for cases where either bound may be negative,
* especially if the bounds are unknown or may be user-specified.
*
* @param innerBound the inclusive inner bound; may be any int, allowing negative
* @param outerBound the exclusive outer bound; may be any int, allowing negative
* @return a pseudorandom int between innerBound (inclusive) and outerBound (exclusive)
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public int nextSignedInt (int innerBound, int outerBound) {
return innerBound + nextUnsignedInt(outerBound - innerBound);
}
/**
* Returns the next pseudorandom, uniformly distributed {@code long}
* value from this random number generator's sequence. The general
* contract of {@code nextLong} is that one {@code long} value is
* pseudorandomly generated and returned.
*
* An individual {@code LaserRNG} can't return all 18-quintillion possible {@code long} values,
* but the full set of 9-quintillion possible random number streams that this class can produce will,
* as a whole, produce all {@code long} values with equal likelihood.
*
* @return the next pseudorandom, uniformly distributed {@code long}
* value from this random number generator's sequence
*/
public long nextLong () {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return z ^ z >>> 26 ^ z >>> 6;
}
/**
* Returns a pseudorandom, uniformly distributed {@code long} value
* between 0 (inclusive) and the specified value (exclusive), drawn from
* this random number generator's sequence. The general contract of
* {@code nextLong} is that one {@code long} value in the specified range
* is pseudorandomly generated and returned. All {@code bound} possible
* {@code long} values are produced with (approximately) equal
* probability, though there is a small amount of bias depending on the bound.
*
*
Note that this advances the state by the same amount as a single call to
* {@link #nextLong()}, which allows methods like {@link #skip(long)} to function
* correctly, but introduces some bias when {@code bound} is very large. This will
* also advance the state if {@code bound} is 0 or negative, so usage with a variable
* bound will advance the state reliably.
*
*
This method has some bias, particularly on larger bounds. Actually measuring
* bias with bounds in the trillions or greater is challenging but not impossible, so
* don't use this for a real-money gambling purpose. The bias isn't especially
* significant, though.
*
* @param bound the upper bound (exclusive). If negative or 0, this always returns 0.
* @return the next pseudorandom, uniformly distributed {@code long}
* value between zero (inclusive) and {@code bound} (exclusive)
* from this random number generator's sequence
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public long nextLong (long bound) {
return nextLong(0L, bound);
}
/**
* Returns a pseudorandom, uniformly distributed {@code long} value between an
* inner bound of 0 (inclusive) and the specified {@code outerBound} (exclusive).
* This is meant for cases where the outer bound may be negative, especially if
* the bound is unknown or may be user-specified. A negative outer bound is used
* as the lower bound; a positive outer bound is used as the upper bound. An outer
* bound of -1, 0, or 1 will always return 0, keeping the bound exclusive (except
* for outer bound 0).
*
*
Note that this advances the state by the same amount as a single call to
* {@link #nextLong()}, which allows methods like {@link #skip(long)} to function
* correctly, but introduces some bias when {@code bound} is very large. This
* method should be about as fast as {@link #nextLong(long)} , unlike the speed
* difference between {@link #nextInt(int)} and {@link #nextSignedInt(int)}.
*
* @param outerBound the outer exclusive bound; may be any long value, allowing negative
* @return a pseudorandom long between 0 (inclusive) and outerBound (exclusive)
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public long nextSignedLong (long outerBound) {
return nextSignedLong(0L, outerBound);
}
/**
* Returns a pseudorandom, uniformly distributed {@code long} value between the
* specified {@code innerBound} (inclusive) and the specified {@code outerBound}
* (exclusive). If {@code outerBound} is less than or equal to {@code innerBound},
* this always returns {@code innerBound}.
*
*
For any case where outerBound might be valid but less than innerBound, you
* can use {@link #nextSignedLong(long, long)}.
*
* @param inner the inclusive inner bound; may be any long, allowing negative
* @param outer the exclusive outer bound; must be greater than innerBound (otherwise this returns innerBound)
* @return a pseudorandom long between innerBound (inclusive) and outerBound (exclusive)
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public long nextLong (long inner, long outer) {
final long rand = nextLong();
if (inner >= outer)
return inner;
final long bound = outer - inner;
final long randLow = rand & 0xFFFFFFFFL;
final long boundLow = bound & 0xFFFFFFFFL;
final long randHigh = (rand >>> 32);
final long boundHigh = (bound >>> 32);
return inner + (randHigh * boundLow >>> 32) + (randLow * boundHigh >>> 32) + randHigh * boundHigh;
}
/**
* Returns a pseudorandom, uniformly distributed {@code long} value between the
* specified {@code innerBound} (inclusive) and the specified {@code outerBound}
* (exclusive). This is meant for cases where either bound may be negative,
* especially if the bounds are unknown or may be user-specified.
*
* @param inner the inclusive inner bound; may be any long, allowing negative
* @param outer the exclusive outer bound; may be any long, allowing negative
* @return a pseudorandom long between innerBound (inclusive) and outerBound (exclusive)
* @see #nextInt(int) Here's a note about the bias present in the bounded generation.
*/
public long nextSignedLong (long inner, long outer) {
final long rand = nextLong();
if (outer < inner) {
long t = outer;
outer = inner + 1L;
inner = t + 1L;
}
final long bound = outer - inner;
final long randLow = rand & 0xFFFFFFFFL;
final long boundLow = bound & 0xFFFFFFFFL;
final long randHigh = (rand >>> 32);
final long boundHigh = (bound >>> 32);
return inner + (randHigh * boundLow >>> 32) + (randLow * boundHigh >>> 32) + randHigh * boundHigh;
}
/**
* Returns the next pseudorandom, uniformly distributed
* {@code boolean} value from this random number generator's
* sequence. The general contract of {@code nextBoolean} is that one
* {@code boolean} value is pseudorandomly generated and returned. The
* values {@code true} and {@code false} are produced with
* (approximately) equal probability.
*
* @return the next pseudorandom, uniformly distributed
* {@code boolean} value from this random number generator's
* sequence
*/
public boolean nextBoolean () {
final long s = stateA += 0xC6BC279692B5C323L;
return (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L) < 0L;
}
/**
* Returns the next pseudorandom, uniformly distributed {@code float}
* value between {@code 0.0} (inclusive) and {@code 1.0} (exclusive)
* from this random number generator's sequence.
*
*
The general contract of {@code nextFloat} is that one
* {@code float} value, chosen (approximately) uniformly from the
* range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), is
* pseudorandomly generated and returned. All 224 possible
* {@code float} values of the form m x 2-24,
* where m is a positive integer less than 224, are
* produced with (approximately) equal probability.
*
*
The hedge "approximately" is used in the foregoing description only
* because the next method is only approximately an unbiased source of
* independently chosen bits. If it were a perfect source of randomly
* chosen bits, then the algorithm shown would choose {@code float}
* values from the stated range with perfect uniformity.
*
* @return the next pseudorandom, uniformly distributed {@code float}
* value between {@code 0.0} and {@code 1.0} from this
* random number generator's sequence
*/
public float nextFloat () {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return ((z ^ z >>> 6) >>> 40) * 0x1p-24f;
}
/**
* Gets a pseudo-random float between 0 (inclusive) and {@code outerBound} (exclusive).
* The outerBound may be positive or negative.
* Exactly the same as {@code nextFloat() * outerBound}.
*
* @param outerBound the exclusive outer bound
* @return a float between 0 (inclusive) and {@code outerBound} (exclusive)
*/
public float nextFloat (float outerBound) {
return nextFloat() * outerBound;
}
/**
* Gets a pseudo-random float between {@code innerBound} (inclusive) and {@code outerBound} (exclusive).
* Either, neither, or both of innerBound and outerBound may be negative; this does not change which is
* inclusive and which is exclusive.
*
* @param innerBound the inclusive inner bound; may be negative
* @param outerBound the exclusive outer bound; may be negative
* @return a float between {@code innerBound} (inclusive) and {@code outerBound} (exclusive)
*/
public float nextFloat (float innerBound, float outerBound) {
return innerBound + nextFloat() * (outerBound - innerBound);
}
/**
* Returns the next pseudorandom, uniformly distributed
* {@code double} value between {@code 0.0} (inclusive) and {@code 1.0}
* (exclusive) from this random number generator's sequence.
*
*
The general contract of {@code nextDouble} is that one
* {@code double} value, chosen (approximately) uniformly from the
* range {@code 0.0d} (inclusive) to {@code 1.0d} (exclusive), is
* pseudorandomly generated and returned.
*
*
The hedge "approximately" is used in the foregoing description only
* because the {@code next} method is only approximately an unbiased
* source of independently chosen bits. If it were a perfect source of
* randomly chosen bits, then the algorithm shown would choose
* {@code double} values from the stated range with perfect uniformity.
*
* @return the next pseudorandom, uniformly distributed {@code double}
* value between {@code 0.0} and {@code 1.0} from this
* random number generator's sequence
*/
public double nextDouble () {
final long s = stateA += 0xC6BC279692B5C323L;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L);
return (z >>> 11 ^ z >>> 37 ^ z >>> 17) * 0x1.0p-53;
}
/**
* Gets a pseudo-random double between 0 (inclusive) and {@code outerBound} (exclusive).
* The outerBound may be positive or negative.
* Exactly the same as {@code nextDouble() * outerBound}.
*
* @param outerBound the exclusive outer bound
* @return a double between 0 (inclusive) and {@code outerBound} (exclusive)
*/
public double nextDouble (double outerBound) {
return nextDouble() * outerBound;
}
/**
* Gets a pseudo-random double between {@code innerBound} (inclusive) and {@code outerBound} (exclusive).
* Either, neither, or both of innerBound and outerBound may be negative; this does not change which is
* inclusive and which is exclusive.
*
* @param innerBound the inclusive inner bound; may be negative
* @param outerBound the exclusive outer bound; may be negative
* @return a double between {@code innerBound} (inclusive) and {@code outerBound} (exclusive)
*/
public double nextDouble (double innerBound, double outerBound) {
return innerBound + nextDouble() * (outerBound - innerBound);
}
/**
* This is just like {@link #nextDouble()}, returning a double between 0 and 1, except that it is inclusive on both 0.0 and 1.0.
* It returns 1.0 extremely rarely, 0.000000000000011102230246251565% of the time if there is no bias in the generator, but it
* can happen. This uses {@link #nextLong(long)} internally, so it may have some bias towards or against specific
* subtly-different results. Other generators here use BitConversion and a very different algorithm, but this avoids
* BitConversion so that it can be copied more easily.
*
* @return a double between 0.0, inclusive, and 1.0, inclusive
*/
public double nextInclusiveDouble () {
// return nextLong(0x20000000000001L) * 0x1p-53;
final long rand = nextLong();
final long bound = 0x20000000000001L;
final long randLow = rand & 0xFFFFFFFFL;
final long randHigh = (rand >>> 32);
final long boundHigh = (bound >>> 32);
return ((randLow * boundHigh >>> 32) + randHigh * boundHigh) * 0x1p-53;
}
/**
* Just like {@link #nextDouble(double)}, but this is inclusive on both 0.0 and {@code outerBound}.
* It may be important to note that it returns outerBound on only 0.000000000000011102230246251565% of calls.
*
* @param outerBound the outer inclusive bound; may be positive or negative
* @return a double between 0.0, inclusive, and {@code outerBound}, inclusive
*/
public double nextInclusiveDouble (double outerBound) {
return nextInclusiveDouble() * outerBound;
}
/**
* Just like {@link #nextDouble(double, double)}, but this is inclusive on both {@code innerBound} and {@code outerBound}.
* It may be important to note that it returns outerBound on only 0.000000000000011102230246251565% of calls, if it can
* return it at all because of floating-point imprecision when innerBound is a larger number.
*
* @param innerBound the inner inclusive bound; may be positive or negative
* @param outerBound the outer inclusive bound; may be positive or negative
* @return a double between {@code innerBound}, inclusive, and {@code outerBound}, inclusive
*/
public double nextInclusiveDouble (double innerBound, double outerBound) {
return innerBound + nextInclusiveDouble() * (outerBound - innerBound);
}
/**
* This is just like {@link #nextFloat()}, returning a float between 0 and 1, except that it is inclusive on both 0.0 and 1.0.
* It returns 1.0 rarely, 0.00000596046412226771% of the time if there is no bias in the generator, but it can happen. This method
* has been tested by generating 268435456 (or 0x10000000) random ints with {@link #nextInt(int)}, and just before the end of that
* it had generated every one of the 16777217 roughly-equidistant floats this is able to produce. Not all seeds and streams are
* likely to accomplish that in the same time, or at all, depending on the generator.
*
* @return a float between 0.0, inclusive, and 1.0, inclusive
*/
public float nextInclusiveFloat () {
return (int)(0x1000001L * (nextLong() & 0xFFFFFFFFL) >> 32) * 0x1p-24f;
}
/**
* Just like {@link #nextFloat(float)}, but this is inclusive on both 0.0 and {@code outerBound}.
* It may be important to note that it returns outerBound on only 0.00000596046412226771% of calls.
*
* @param outerBound the outer inclusive bound; may be positive or negative
* @return a float between 0.0, inclusive, and {@code outerBound}, inclusive
*/
public float nextInclusiveFloat (float outerBound) {
return nextInclusiveFloat() * outerBound;
}
/**
* Just like {@link #nextFloat(float, float)}, but this is inclusive on both {@code innerBound} and {@code outerBound}.
* It may be important to note that it returns outerBound on only 0.00000596046412226771% of calls, if it can return
* it at all because of floating-point imprecision when innerBound is a larger number.
*
* @param innerBound the inner inclusive bound; may be positive or negative
* @param outerBound the outer inclusive bound; may be positive or negative
* @return a float between {@code innerBound}, inclusive, and {@code outerBound}, inclusive
*/
public float nextInclusiveFloat (float innerBound, float outerBound) {
return innerBound + nextInclusiveFloat() * (outerBound - innerBound);
}
/**
* Returns the next pseudorandom, Gaussian ("normally") distributed
* {@code double} value with mean {@code 0.0} and standard
* deviation {@code 1.0} from this random number generator's sequence.
*
* The general contract of {@code nextGaussian} is that one
* {@code double} value, chosen from (approximately) the usual
* normal distribution with mean {@code 0.0} and standard deviation
* {@code 1.0}, is pseudorandomly generated and returned.
*
* This uses an inverse transform sample method to generate its random
* values, using a method called probit(). The algorithm used was
* written by Peter John Acklam, and implemented by Sherali Karimov.
* Original source.
* Information on the algorithm.
* As this is written, it can return a maximum result of 8.209536145151493,
* and a minimum result of -38.5 . 38.5 only occurs 1 in every (2 to the 53)
* calls, on average, and all other results are between -8.209536145151493
* and 8.209536145151493 . Note, this implementation is different from the
* one in EnhancedRandom only to permit copying this class more easily;
* EnhancedRandom normally uses another class, Ziggurat, to more efficiently
* generate normally-distributed doubles.
*
* @return the next pseudorandom, Gaussian ("normally") distributed
* {@code double} value with mean {@code 0.0} and standard deviation
* {@code 1.0} from this random number generator's sequence
*/
public double nextGaussian () {
final double d = nextDouble();
if (d == 0) {
return -38.5;
} else if (d < 0.02425) {
final double q = Math.sqrt(-2.0 * Math.log(d));
return (((((-7.784894002430293e-03 * q - 3.223964580411365e-01) * q - 2.400758277161838e+00) * q - 2.549732539343734e+00) * q + 4.374664141464968e+00) * q + 2.938163982698783e+00) / (
(((7.784695709041462e-03 * q + 3.224671290700398e-01) * q + 2.445134137142996e+00) * q + 3.754408661907416e+00) * q + 1.0);
} else if (0.97575 < d) {
final double q = Math.sqrt(-2.0 * Math.log(1 - d));
return -(((((-7.784894002430293e-03 * q - 3.223964580411365e-01) * q - 2.400758277161838e+00) * q - 2.549732539343734e+00) * q + 4.374664141464968e+00) * q + 2.938163982698783e+00) / (
(((7.784695709041462e-03 * q + 3.224671290700398e-01) * q + 2.445134137142996e+00) * q + 3.754408661907416e+00) * q + 1.0);
} else {
final double q = d - 0.5;
final double r = q * q;
return (((((-3.969683028665376e+01 * r + 2.209460984245205e+02) * r - 2.759285104469687e+02) * r + 1.383577518672690e+02) * r - 3.066479806614716e+01) * r + 2.506628277459239e+00) * q / (
((((-5.447609879822406e+01 * r + 1.615858368580409e+02) * r - 1.556989798598866e+02) * r + 6.680131188771972e+01) * r - 1.328068155288572e+01) * r + 1.0);
}
}
/**
* Advances or rolls back the {@code LaserRandom}' state without actually generating each number. Skips forward
* or backward a number of steps specified by advance, where a step is equal to one call to {@link #nextLong()},
* and returns the random number produced at that step. Negative numbers can be used to step backward, or 0 can be
* given to get the most-recently-generated long from {@link #nextLong()}.
*
*
Note that none of the number-generating methods here advance state differently from {@link #nextLong()} except
* for the Stream APIs. This is somewhat unusual; in many generators, calls to {@link #nextInt(int)} and similar
* bounded-range random generators can advance the state by a variable amount. Using a fixed advance permits this
* method and also allows guaranteeing the cycle length (also called period), but introduces a tiny amount of bias
* for some bounds (mostly very large ones).
*
* @param advance Number of future generations to skip over; can be negative to backtrack, 0 gets the most-recently-generated number
* @return the random long generated after skipping forward or backwards by {@code advance} numbers
*/
public long skip (long advance) {
final long s = stateA += 0xC6BC279692B5C323L * advance;
final long z = (s ^ s >>> 31) * (stateB += 0x9E3779B97F4A7C16L * advance);
return z ^ z >>> 26 ^ z >>> 6;
}
public long previousLong () {
final long s = stateA;
final long z = (s ^ s >>> 31) * stateB;
stateA -= 0xC6BC279692B5C323L;
stateB -= 0x9E3779B97F4A7C16L;
return z ^ z >>> 26 ^ z >>> 6;
}
/**
* Creates a new {@code LaserRandom} with identical states to this one, so if the same LaserRandom methods are
* called on this object and its copy (in the same order), the same outputs will be produced. This is not
* guaranteed to copy the inherited state of the {@link Random} parent class, so if you call methods that are
* only implemented by Random and not LaserRandom, the results may differ.
*
* @return a deep copy of this LaserRandom.
*/
public LaserRandom copy () {
return new LaserRandom(stateA, stateB);
}
/**
* Gets a long that identifies which stream of numbers this generator is producing; this stream identifier is always
* an odd long and won't change by generating numbers. It is determined at construction and will usually (not
* always) change if {@link #setStateA(long)} or {@link #setStateB(long)} are called. Each stream is a
* probably-unique sequence of 2 to the 64 longs, where approximately 1/3 of all possible longs will not ever occur
* (while others occur twice or more), but this set of results is different for every stream. There are 2 to the 63
* possible streams, one for every odd long.
*
* @return an odd long that identifies which stream this LaserRandom is generating from
*/
public long getStream () {
return stateB - stateA * 0x3085776F0FBEB7F2L; // 0x3085776F0FBEB7F2L == 0x1743CE5C6E1B848BL * 0x9E3779B97F4A7C16L
}
/**
* Returns true if a random value between 0 and 1 is less than the specified value.
*
* @param chance a float between 0.0 and 1.0; higher values are more likely to result in true
* @return a boolean selected with the given {@code chance} of being true
*/
public boolean nextBoolean (float chance) {
return nextFloat() < chance;
}
/**
* Returns -1 or 1, randomly.
*
* @return -1 or 1, selected with approximately equal likelihood
*/
public int nextSign () {
return 1 | nextInt() >> 31;
}
/**
* Returns a triangularly distributed random number between -1.0 (exclusive) and 1.0 (exclusive), where values around zero are
* more likely. Advances the state twice.
*
* This is an optimized version of {@link #nextTriangular(float, float, float) randomTriangular(-1, 1, 0)}
*/
public float nextTriangular () {
return nextFloat() - nextFloat();
}
/**
* Returns a triangularly distributed random number between {@code -max} (exclusive) and {@code max} (exclusive), where values
* around zero are more likely. Advances the state twice.
*
* This is an optimized version of {@link #nextTriangular(float, float, float) randomTriangular(-max, max, 0)}
*
* @param max the upper limit
*/
public float nextTriangular (float max) {
return (nextFloat() - nextFloat()) * max;
}
/**
* Returns a triangularly distributed random number between {@code min} (inclusive) and {@code max} (exclusive), where the
* {@code mode} argument defaults to the midpoint between the bounds, giving a symmetric distribution. Advances the state once.
*
* This method is equivalent of {@link #nextTriangular(float, float, float) randomTriangular(min, max, (min + max) * 0.5f)}
*
* @param min the lower limit
* @param max the upper limit
*/
public float nextTriangular (float min, float max) {
return nextTriangular(min, max, (min + max) * 0.5f);
}
/**
* Returns a triangularly distributed random number between {@code min} (inclusive) and {@code max} (exclusive), where values
* around {@code mode} are more likely. Advances the state once.
*
* @param min the lower limit
* @param max the upper limit
* @param mode the point around which the values are more likely
*/
public float nextTriangular (float min, float max, float mode) {
float u = nextFloat();
float d = max - min;
if (u <= (mode - min) / d) {return min + (float)Math.sqrt(u * d * (mode - min));}
return max - (float)Math.sqrt((1 - u) * d * (max - mode));
}
/**
* Gets a randomly-selected item from the given array, which must be non-null and non-empty
*
* @param array a non-null, non-empty array of {@code T} items
* @param any reference type
* @return a random item from {@code array}
* @throws NullPointerException if array is null
* @throws IndexOutOfBoundsException if array is empty
*/
public T randomElement (T[] array) {
return array[nextInt(array.length)];
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items an int array; must be non-null
*/
public void shuffle (int[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
int temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a long array; must be non-null
*/
public void shuffle (long[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
long temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a float array; must be non-null
*/
public void shuffle (float[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
float temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a char array; must be non-null
*/
public void shuffle (char[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
char temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a byte array; must be non-null
*/
public void shuffle (byte[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
byte temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a double array; must be non-null
*/
public void shuffle (double[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
double temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a short array; must be non-null
*/
public void shuffle (short[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
short temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items a boolean array; must be non-null
*/
public void shuffle (boolean[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
boolean temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
/**
* Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
*
* @param items an array of some reference type; must be non-null but may contain null items
*/
public void shuffle (T[] items) {
for (int i = items.length - 1; i > 0; i--) {
int ii = nextInt(i + 1);
T temp = items[i];
items[i] = items[ii];
items[ii] = temp;
}
}
@Override
public boolean equals (Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
LaserRandom that = (LaserRandom)o;
if (stateA != that.stateA)
return false;
return stateB == that.stateB;
}
/**
* This String conversion uses base-10 numbers for the states, unlike all other EnhancedRandom implementations, which use base-16.
* This is done here to avoid a dependency on Base, allowing this class to be copied more easily.
* @return a String description of this LaserRandom and its two states
*/
@Override
public String toString () {
return "LaserRandom{" + "stateA=" + stateA + "L, stateB=" + stateB + "L}";
}
}