Package squidpony.squidmath
Class BasicRandom64
java.lang.Object
java.util.Random
squidpony.squidmath.BasicRandom64
- All Implemented Interfaces:
Serializable
,RandomnessSource
public class BasicRandom64 extends Random implements RandomnessSource, Serializable
A high-quality and very fast RNG that has no apparent visual artifacts here; uses Mark Overton's CMR subcycle
generator type, with a multiplication on the output. This is meant to be an answer to when people ask for a
bare-minimum generator that's still "good enough" for games. It still passes at least 8TB of PractRand testing and
passes TestU01 with both the bits in normal forward order and in reversed bit order, which is remarkable for a
generator this small and simple. It has an unknown period that is fairly high; unless the seed used puts the
generator in a worse cycle (some of which have a much lower period, like the seed 0), the period probably won't be
exhausted without hours (possibly days) of pure random number generation. It cannot produce all possible longs in its
longest cycle, and it can't produce even a fraction of all possible longs in its smallest cycle.
This implements RandomnessSource, but if you just want to copy this class with no dependencies, then the class declaration can easily be changed to
This Dr. Dobb's article has more on this type of generator. A multiplication applied to the output of a CMR seems to be enough to pass stringent testing, which is amazing.
This implements RandomnessSource, but if you just want to copy this class with no dependencies, then the class declaration can easily be changed to
public class BasicRandom64 extends Random implements Serializable
without any other changes. Note, it does extend java.util.Random for additional ease of integration, but doesn't use
the slow synchronized
keyword that Random's implementations do.
This Dr. Dobb's article has more on this type of generator. A multiplication applied to the output of a CMR seems to be enough to pass stringent testing, which is amazing.
- Author:
- Mark Overton, Tommy Ettinger
- See Also:
- Serialized Form
-
Field Summary
Fields Modifier and Type Field Description long
state
-
Constructor Summary
Constructors Constructor Description BasicRandom64()
Callsseed(int)
with a random int value (obtained usingMath.random()
).BasicRandom64(int seed)
The recommended constructor, this guarantees the generator will have a period of at least 2 to the 20 (roughly one million, but most if not all initial states will have much longer periods).BasicRandom64(long seed)
LikeBasicRandom64(int)
, this doesn't use the seed as-is, and instead uses it to get a valid state (which is a long internally). -
Method Summary
Modifier and Type Method Description BasicRandom64
copy()
Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the copy, both will generate the same sequence of random numbers from the point copy() was called.long
getState()
int
next(int bits)
Gets an int with at most the specified amount of bits; don't confuse this withnextInt(int)
, which gets a number between 0 and its int argument, where this draws from a different (larger) range of random results.int
nextInt()
int
nextInt(int bound)
Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), or 0 if the bound is 0.long
nextLong()
Using this method, any algorithm that needs to efficiently generate more than 32 bits of random data can interface with this randomness source.long
nextLong(long bound)
Exclusive on bound (which must be positive), with an inner bound of 0.void
seed(int s)
Seeds the state using all bits of the given ints
.void
setSeed(long seed)
Sets the seed using a long, passing its argument tosetState(long)
.void
setState(long seed)
<T> T[]
shuffle(T[] elements)
Shuffle an array using the Fisher-Yates algorithm and returns a shuffled copy, freshly-allocated, without modifying elements.<T> List<T>
shuffleInPlace(List<T> elements)
Shuffles a Collection of T items in-place using the Fisher-Yates algorithm.<T> T[]
shuffleInPlace(T[] elements)
Shuffles an array in-place using the Fisher-Yates algorithm.<T> T[]
shuffleInPlace(T[] elements, int length)
Shuffles an array in-place using the Fisher-Yates algorithm, affecting indices from 0 (inclusive) to length (exclusive).protected static <T> void
swap(T[] arr, int pos1, int pos2)
Mutates the array arr by switching the contents at pos1 and pos2.
-
Field Details
-
Constructor Details
-
BasicRandom64
public BasicRandom64()Callsseed(int)
with a random int value (obtained usingMath.random()
). -
BasicRandom64
The recommended constructor, this guarantees the generator will have a period of at least 2 to the 20 (roughly one million, but most if not all initial states will have much longer periods). All ints are permissible values for theseed
parameter.- Parameters:
seed
- any int; will be used to get the actual state used in the generator (which is a long internally)
-
BasicRandom64
LikeBasicRandom64(int)
, this doesn't use the seed as-is, and instead uses it to get a valid state (which is a long internally). If you want to duplicate the state of another BasicRandom64, get the existing state either with the fieldstate
or withgetState()
(you could store the state and load it later at this stage), then make some new BasicRandom64 (such as withnew BasicRandom64(0);
) and callsetState(long)
with the previous state. You can also usecopy()
.- Parameters:
seed
- any long; will be mixed around and given toseed(int)
as an int, not used as-is
-
-
Method Details
-
seed
Seeds the state using all bits of the given ints
. Between 33554432 and 4294967296 seeds are possible, with the actual count probably much closer to 4294967296. This treats the top 25 bits ofs
(moved to the bottom, plus 1, to avoid a seed of 0) as the starting point and then generates the next state at most 127 times, with each generated state taking less time thannextLong()
. Some of the starting states are entirely possible to be within 127 steps of another starting state, so not all seeds are necessarily unique. This is not guaranteed to put the generator on an optimal subcycle, but it is guaranteed that any subcycle will have a period of at least 1048575.- Parameters:
s
- all bits are used, none verbatim (0 is tolerated)
-
getState
-
setState
-
nextLong
Description copied from interface:RandomnessSource
Using this method, any algorithm that needs to efficiently generate more than 32 bits of random data can interface with this randomness source. Get a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive).- Specified by:
nextLong
in interfaceRandomnessSource
- Overrides:
nextLong
in classRandom
- Returns:
- a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive)
-
next
Gets an int with at most the specified amount of bits; don't confuse this withnextInt(int)
, which gets a number between 0 and its int argument, where this draws from a different (larger) range of random results. For example,next(2)
can return any 2-bit int, which is limited to 0, 1, 2, or 3. Note that if you request 0 bits, this can give you any int (32 bits).- Specified by:
next
in interfaceRandomnessSource
- Overrides:
next
in classRandom
- Parameters:
bits
- the number of bits to get, from 1 to 32- Returns:
- an int with at most the specified bits
-
nextInt
-
nextInt
Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result.
Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ -
nextLong
Exclusive on bound (which must be positive), with an inner bound of 0. If bound is negative or 0 this always returns 0.
Credit for this method goes to Rafael Baptista's blog for the original idea, and the JDK10 Math class' usage of Karatsuba multiplication for the current algorithm. This method is drastically faster than the previous implementation when the bound varies often (roughly 4x faster, possibly more). It also always gets exactly one random long, so by default it advances the state as much asnextLong()
.- Parameters:
bound
- the outer exclusive bound; should be positive, otherwise this always returns 0L- Returns:
- a random long between 0 (inclusive) and bound (exclusive)
-
setSeed
Sets the seed using a long, passing its argument tosetState(long)
. That method just sets the public fieldstate
to its argument currently, but it may do more to ensure cycle length in the future. -
swap
Mutates the array arr by switching the contents at pos1 and pos2.- Parameters:
arr
- an array of T; must not be nullpos1
- an index into arr; must be at least 0 and no greater than arr.lengthpos2
- an index into arr; must be at least 0 and no greater than arr.length
-
shuffle
Shuffle an array using the Fisher-Yates algorithm and returns a shuffled copy, freshly-allocated, without modifying elements.
Wikipedia has more on this algorithm.- Parameters:
elements
- an array of T; will not be modified- Returns:
- a shuffled copy of elements
-
shuffleInPlace
Shuffles an array in-place using the Fisher-Yates algorithm, affecting indices from 0 (inclusive) to length (exclusive). May be useful with libGDX Array instances, which can be shuffled withrandom.shuffleInPlace(arr.items, arr.size)
. If you don't want the array modified, useshuffle(Object[])
.
Wikipedia has more on this algorithm.- Parameters:
elements
- an array of T; will be modified- Returns:
- elements after shuffling it in-place
-
shuffleInPlace
Shuffles an array in-place using the Fisher-Yates algorithm. If you don't want the array modified, useshuffle(Object[])
.
Wikipedia has more on this algorithm.- Parameters:
elements
- an array of T; will be modified- Returns:
- elements after shuffling it in-place
-
shuffleInPlace
Shuffles a Collection of T items in-place using the Fisher-Yates algorithm. This only shuffles List data structures.
Wikipedia has more on this algorithm.- Type Parameters:
T
- can be any non-primitive type.- Parameters:
elements
- a List of T; will be modified- Returns:
- elements after shuffling it in-place
-
copy
Description copied from interface:RandomnessSource
Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to copy the state so it isn't shared, usually, and produce a new value with the same exact state.- Specified by:
copy
in interfaceRandomnessSource
- Returns:
- a copy of this RandomnessSource
-