Package squidpony.squidmath
Class AbstractRNG
java.lang.Object
squidpony.squidmath.AbstractRNG
- All Implemented Interfaces:
Serializable
,IRNG
,RandomnessSource
- Direct Known Subclasses:
DistributedRNG
,GWTRNG
,MoonwalkRNG
,SilkRNG
,TweakRNG
public abstract class AbstractRNG extends Object implements IRNG
A helper class for implementing
Big thanks to smelc for the concept in his hgameshrogue library.
IRNG
without so much busy-work.
You need to provide implementations for the abstract methods nextInt()
, next(int)
,
nextLong()
, nextBoolean()
, nextDouble()
, nextFloat()
, copy()
, and
toSerializable()
, many of which may be built off of each other and some of which have sample code in their
documentation strings in this class.
Big thanks to smelc for the concept in his hgameshrogue library.
- Author:
- Tommy Ettinger, smelC
- See Also:
- Serialized Form
-
Constructor Summary
Constructors Constructor Description AbstractRNG()
-
Method Summary
Modifier and Type Method Description double
between(double min, double max)
Returns a value from a uniform distribution from min (inclusive) to max (exclusive).int
between(int min, int max)
Returns a value between min (inclusive) and max (exclusive) as ints.long
between(long min, long max)
Returns a value between min (inclusive) and max (exclusive) as longs.abstract IRNG
copy()
Creates a copy of this IRNG; it will generate the same random numbers, given the same calls in order, as this IRNG at the point copy() is called.<T> T
getRandomElement(Collection<T> coll)
Returns a random element from the provided Collection, which should have predictable iteration order if you want predictable behavior for identical RNG seeds, though it will get a random element just fine for any Collection (just not predictably in all cases).<T> T
getRandomElement(List<T> list)
Returns a random element from the provided list.<T> T
getRandomElement(T[] array)
Returns a random element from the provided array and maintains object type.abstract int
next(int bits)
Get up to 32 bits (inclusive) of random output; the int this produces will not require more thanbits
bits to represent.abstract boolean
nextBoolean()
Get a random bit of state, interpreted as true or false with approximately equal likelihood.abstract double
nextDouble()
Gets a random double between 0.0 inclusive and 1.0 exclusive.double
nextDouble(double outer)
This returns a random double between 0.0 (inclusive) and outer (exclusive).abstract float
nextFloat()
Gets a random float between 0.0f inclusive and 1.0f exclusive.float
nextFloat(float outer)
This returns a random float between 0.0f (inclusive) and outer (exclusive).abstract int
nextInt()
Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive).int
nextInt(int bound)
Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or negative.abstract long
nextLong()
Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).long
nextLong(long bound)
Exclusive on bound (which must be positive), with an inner bound of 0.int
nextSignedInt(int bound)
Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), or 0 if the bound is 0.long
nextSignedLong(long bound)
Exclusive on bound (which may be positive or negative), with an inner bound of 0.int[]
randomOrdering(int length)
Generates a random permutation of the range from 0 (inclusive) to length (exclusive).int[]
randomOrdering(int length, int[] dest)
Generates a random permutation of the range from 0 (inclusive) to length (exclusive) and stores it in the dest parameter, avoiding allocations.<T> T[]
randomPortion(T[] data, T[] output)
Gets a random portion of data (an array), assigns that portion to output (an array) so that it fills as much as it can, and then returns output.<T> ArrayList<T>
shuffle(Collection<T> elements)
Shuffles aCollection
of T using the Fisher-Yates algorithm and returns an ArrayList of T.<T> ArrayList<T>
shuffle(Collection<T> elements, ArrayList<T> buf)
Shuffles aCollection
of T using the Fisher-Yates algorithm and puts it in a buffer.<T> T[]
shuffle(T[] elements)
Shuffle an array using the Fisher-Yates algorithm and returns a shuffled copy, freshly-allocated, without modifying elements.<T> T[]
shuffle(T[] elements, T[] dest)
Shuffle an array using the Fisher-Yates algorithm.<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.protected static <T> void
swap(T[] arr, int pos1, int pos2)
Mutates the array arr by switching the contents at pos1 and pos2.abstract Serializable
toSerializable()
Gets a view of this IRNG in a way that implementsSerializable
, which may simply be this IRNG if it implements Serializable as well as IRNG.
-
Constructor Details
-
AbstractRNG
public AbstractRNG()
-
-
Method Details
-
next
Get up to 32 bits (inclusive) of random output; the int this produces will not require more thanbits
bits to represent.- Specified by:
next
in interfaceIRNG
- Specified by:
next
in interfaceRandomnessSource
- Parameters:
bits
- an int between 1 and 32, both inclusive- Returns:
- a random number that fits in the specified number of bits
-
nextInt
Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive). -
nextInt
Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or negative. -
nextLong
Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).- Specified by:
nextLong
in interfaceIRNG
- Specified by:
nextLong
in interfaceRandomnessSource
- Returns:
- a 64-bit random long.
-
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()
; subclasses can generate two ints instead of one long if they prefer. -
nextBoolean
Get a random bit of state, interpreted as true or false with approximately equal likelihood.
Note: This is abstract because some implementations may be best served by usingnext(int)
to get 1 bit, returningnext(1) == 1
, but others will get much better results with a sign check by calling their choice ofnextInt()
ornextLong()
and returningnextInt() < 0
ornextLong < 0L
. For example, an implementation that uses a linear congruential generator without truncating some lower bits will have very-low-period results for the bottom bit (alternating true and false), but perfectly fine results from a sign check. There are tested issues on the bottom (at least 2) bits ofXoRoRNG
, but again not on a sign check.- Specified by:
nextBoolean
in interfaceIRNG
- Returns:
- a random boolean.
-
nextDouble
Gets a random double between 0.0 inclusive and 1.0 exclusive. This returns a maximum of 0.9999999999999999 because that is the largest double value that is less than 1.0 .
This is abstract because some generators may natively work with double or float values, but others may need to convert a long to a double as with(nextLong() & 0x1fffffffffffffL) * 0x1p-53
, which is recommended if longs are fast to produce.- Specified by:
nextDouble
in interfaceIRNG
- Returns:
- a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive)
-
nextDouble
This returns a random double between 0.0 (inclusive) and outer (exclusive). The value for outer can be positive or negative. Because of how math on doubles works, there are at most 2 to the 53 values this can return for any given outer bound, and very large values for outer will not necessarily produce all numbers you might expect.- Specified by:
nextDouble
in interfaceIRNG
- Parameters:
outer
- the outer exclusive bound as a double; can be negative or positive- Returns:
- a double between 0.0 (inclusive) and outer (exclusive)
-
nextFloat
Gets a random float between 0.0f inclusive and 1.0f exclusive. This returns a maximum of 0.99999994 because that is the largest float value that is less than 1.0f .
This is abstract because some generators may natively work with double or float values, but others may need to convert an int or long to a float as with(nextInt() & 0xffffff) * 0x1p-24f
,(nextLong() & 0xffffffL) * 0x1p-24f
, ornext(24) * 0x1p-24f
, any of which can work when the method they call is high-quality and fast. You probably would want to use nextInt() or next() if your implementation is natively 32-bit and is slower at producing longs, for example. -
nextFloat
This returns a random float between 0.0f (inclusive) and outer (exclusive). The value for outer can be positive or negative. Because of how math on floats works, there are at most 2 to the 24 values this can return for any given outer bound, and very large values for outer will not necessarily produce all numbers you might expect. -
nextSignedLong
Exclusive on bound (which may be positive or negative), with an inner bound of 0. If bound is negative this returns a negative long; if bound is positive this returns a positive long. The bound can even be 0, which will cause this to return 0L every time. This uses a biased technique to get numbers from large ranges, but the amount of bias is incredibly small (expected to be under 1/1000 if enough random ranged numbers are requested, which is about the same as an unbiased method that was also considered). It may have noticeable bias if the generator's period is exhausted by only calls to this method. Unlike all unbiased methods, this advances the state by an equivalent to exactly one call tonextLong()
, where rejection sampling would sometimes advance by one call, but other times by arbitrarily many more.
Credit for this method goes to Rafael Baptista's blog for the original idea, and the JDK10 Math class' usage of Hacker's Delight code 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()
; subclasses that are better at generating ints can override this and generate two ints instead of one long that needs separating internally.- Specified by:
nextSignedLong
in interfaceIRNG
- Parameters:
bound
- the outer exclusive bound; can be positive or negative- Returns:
- a random long between 0 (inclusive) and bound (exclusive)
-
nextSignedInt
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/- Specified by:
nextSignedInt
in interfaceIRNG
- Parameters:
bound
- the outer bound (exclusive), can be negative or positive- Returns:
- the found number
-
between
Returns a value between min (inclusive) and max (exclusive) as ints.
The inclusive and exclusive behavior is to match the behavior of the similar method that deals with floating point values.
Ifmin
andmax
happen to be the same,min
is returned (breaking the exclusive behavior, but it's convenient to do so). -
between
Returns a value between min (inclusive) and max (exclusive) as longs.
The inclusive and exclusive behavior is to match the behavior of the similar method that deals with floating point values.
Ifmin
andmax
happen to be the same,min
is returned (breaking the exclusive behavior, but it's convenient to do so). -
between
Returns a value from a uniform distribution from min (inclusive) to max (exclusive). -
getRandomElement
Returns a random element from the provided array and maintains object type.- Specified by:
getRandomElement
in interfaceIRNG
- Type Parameters:
T
- the type of the returned object- Parameters:
array
- the array to get an element from- Returns:
- the randomly selected element
-
getRandomElement
Returns a random element from the provided list. If the list is empty then null is returned. This will perform well on Lists that allow random access, but will not perform as well onLinkedList
or similar classes that need to iterate one-by-one in theirList.get(int)
method.- Specified by:
getRandomElement
in interfaceIRNG
- Type Parameters:
T
- the type of the returned object- Parameters:
list
- the list to get an element from- Returns:
- the randomly selected element
-
getRandomElement
Returns a random element from the provided Collection, which should have predictable iteration order if you want predictable behavior for identical RNG seeds, though it will get a random element just fine for any Collection (just not predictably in all cases). If you give this a Set, it should be a LinkedHashSet or some form of sorted Set like TreeSet if you want predictable results. Any List or Queue should be fine. Map does not implement Collection, thank you very much Java library designers, so you can't actually pass a Map to this, though you can pass the keys or values. If coll is empty, returns null.
Requires iterating through a random amount of coll's elements, so performance depends on the size of coll but is likely to be decent, as long as iteration isn't unusually slow. This replacesgetRandomElement(Queue)
, since Queue implements Collection and the older Queue-using implementation was probably less efficient.
You should generally prefergetRandomElement(List)
whenever possible, or in some cases you can use methods that get a random value on the Collection (or Map, in the case of OrderedMap) itself.- Specified by:
getRandomElement
in interfaceIRNG
- Type Parameters:
T
- the type of the returned object- Parameters:
coll
- the Collection to get an element from; remember, Map does not implement Collection- Returns:
- the randomly selected element
-
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. -
shuffleInPlace
Shuffles an array in-place using the Fisher-Yates algorithm. If you don't want the array modified, useshuffle(Object[], Object[])
.
Wikipedia has more on this algorithm.- Specified by:
shuffleInPlace
in interfaceIRNG
- Type Parameters:
T
- can be any non-primitive type.- Parameters:
elements
- an array of T; will be modified- Returns:
- elements after shuffling it in-place
-
shuffle
Shuffle an array using the Fisher-Yates algorithm. If possible, create a new array or reuse an existing array with the same length as elements and pass it in as dest; the dest array will contain the shuffled contents of elements and will also be returned as-is. If dest does not have the same length as elements, this will throw an IllegalArgumentException
Wikipedia has more on this algorithm.- Specified by:
shuffle
in interfaceIRNG
- Type Parameters:
T
- can be any non-primitive type.- Parameters:
elements
- an array of T; will not be modifieddest
- Where to put the shuffle. If it does not have the same length aselements
, this will throw an IllegalArgumentException.- Returns:
dest
after modifications
-
shuffle
Shuffles aCollection
of T using the Fisher-Yates algorithm and returns an ArrayList of T.
Wikipedia has more on this algorithm. -
shuffle
Shuffles aCollection
of T using the Fisher-Yates algorithm and puts it in a buffer. The result is allocated ifbuf
is null or ifbuf
isn't empty, otherwiseelements
is poured intobuf
.
Wikipedia has more on this algorithm.- Specified by:
shuffle
in interfaceIRNG
- Type Parameters:
T
- can be any non-primitive type.- Parameters:
elements
- a Collection of T; will not be modifiedbuf
- a buffer as an ArrayList that will be filled with the shuffled contents of elements; if null or non-empty, a new ArrayList will be allocated and returned- Returns:
- a shuffled ArrayList containing the whole of elements in pseudo-random order, which may be
buf
-
shuffleInPlace
Shuffles a Collection of T items in-place using the Fisher-Yates algorithm. This only shuffles List data structures. If you don't want the array modified, useshuffle(Collection)
, which returns a List as well.
Wikipedia has more on this algorithm.- Specified by:
shuffleInPlace
in interfaceIRNG
- Type Parameters:
T
- can be any non-primitive type.- Parameters:
elements
- a Collection of T; will be modified- Returns:
- elements after shuffling it in-place
-
randomOrdering
Generates a random permutation of the range from 0 (inclusive) to length (exclusive). Useful for passing to OrderedMap or OrderedSet's reorder() methods.- Specified by:
randomOrdering
in interfaceIRNG
- Parameters:
length
- the size of the ordering to produce- Returns:
- a random ordering containing all ints from 0 to length (exclusive)
-
randomOrdering
Generates a random permutation of the range from 0 (inclusive) to length (exclusive) and stores it in the dest parameter, avoiding allocations. Useful for passing to OrderedMap or OrderedSet's reorder() methods.- Specified by:
randomOrdering
in interfaceIRNG
- Parameters:
length
- the size of the ordering to produce; the smaller ofdest.length
and length will be useddest
- the destination array; will be modified- Returns:
- dest, filled with a random ordering containing all ints from 0 to length (exclusive)
-
randomPortion
Gets a random portion of data (an array), assigns that portion to output (an array) so that it fills as much as it can, and then returns output. Will only use a given position in the given data at most once; uses a Feistel Network to accomplish this without allocations. Internally, makes 2 calls tonextInt()
, regardless of the data being randomized.
Uses approximately the same code asLowStorageShuffler
, but without any object or array allocations.- Specified by:
randomPortion
in interfaceIRNG
- Type Parameters:
T
- can be any non-primitive type.- Parameters:
data
- an array of T; will not be modified.output
- an array of T that will be overwritten; should always be instantiated with the portion length- Returns:
- output, after
Math.min(output.length, data.length)
unique items have been put into it from data
-
copy
Creates a copy of this IRNG; it will generate the same random numbers, given the same calls in order, as this IRNG at the point copy() is called. The copy will not share references with this IRNG. If this IRNG does not permit copying itself, it is suggested to either throw anUnsupportedOperationException
or return a new IRNG of the same type but with a random seed, with the latter meant as a partial defense against cheating.
This is abstract because every implementation is likely to have different specifics for this.- Specified by:
copy
in interfaceIRNG
- Specified by:
copy
in interfaceRandomnessSource
- Returns:
- a copy of this IRNG
-
toSerializable
Gets a view of this IRNG in a way that implementsSerializable
, which may simply be this IRNG if it implements Serializable as well as IRNG.
For implementors: It is suggested to return anRNG
initialized by callingRNG(long)
withnextLong()
if you are unable to save the current state of this IRNG and the caller still needs something saved. This won't preserve the current state or the choice of IRNG implementation, however, so it is simply a last resort in case you don't want to throw an exception.- Specified by:
toSerializable
in interfaceIRNG
- Returns:
- a
Serializable
view of this IRNG or a similar one; may bethis
-