Package squidpony.squidmath
Class GWTRNG
java.lang.Object
squidpony.squidmath.AbstractRNG
squidpony.squidmath.GWTRNG
- All Implemented Interfaces:
Serializable
,IRNG
,IStatefulRNG
,RandomnessSource
,StatefulRandomness
public final class GWTRNG extends AbstractRNG implements IStatefulRNG, Serializable
An IRNG implementation that is meant to provide random numbers very quickly when targeting GWT but also to produce
the same numbers when used on desktop, Android, or other platforms, and that can have its state read as a
StatefulRandomness. This uses the same algorithm as
Be advised: if you subtract
Original version here for xoroshiro64**.
Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) Ported and modified in 2018 and 2019 by Tommy Ettinger
Starfish32RNG
, which means it has two 32-bit ints for
state and a period of 0xFFFFFFFFFFFFFFFF (2 to the 64 minus 1), while passing 32TB of PractRand tests without any
failures or anomalies (so its quality is very good). This previously used Lathe32RNG
's algorithm, which is a
tiny bit faster on desktop and a fair amount faster on GWT, but can't produce all long values and produces some more
often than others. Unlike RNG
, there is no RandomnessSource that can be swapped out, but also somewhat less
indirection on common calls like nextInt()
and nextFloat()
. Although this implements
StatefulRandomness
, it is not recommended to use this as the RandomnessSource for a StatefulRNG; you should
use Starfish32RNG
if you want the larger API provided by StatefulRNG and/or RNG while keeping similar, though
probably slightly weaker, GWT performance relative to this class. Any performance measurements on GWT depend heavily
on the browser; in some versions of Chrome and Chromium, this performs almost exactly as well as Lathe32RNG, but in
newer versions it lags behind by a small factor. It tends to be very fast in the current Firefox (September 2018).
Be advised: if you subtract
0x9E3779BD
from every output, that modified output will fail some tests reliably.
Similar numbers may also cause this result, though it isn't clear if this is ever relevant in actual usage. Part of
the reason Lathe32RNG was switched out was because its behavior on AbstractRNG.between(int, int)
was poor, but it
doesn't seem to be for this version.
Original version here for xoroshiro64**.
Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) Ported and modified in 2018 and 2019 by Tommy Ettinger
- Author:
- Sebastiano Vigna, David Blackman, Tommy Ettinger (if there's a flaw, use SquidLib's issues and don't bother Vigna or Blackman, the algorithm here has been adjusted from their work)
- See Also:
- Serialized Form
-
Field Summary
-
Constructor Summary
Constructors Constructor Description GWTRNG()
Creates a new generator seeded using two calls to Math.random().GWTRNG(int seed)
Constructs this GWTRNG by dispersing the bits of seed usingsetSeed(int)
across the two parts of state this has.GWTRNG(int stateA, int stateB)
Constructs this GWTRNG by callingsetState(int, int)
on stateA and stateB as given; see that method for the specific details (stateA and stateB are kept as-is unless they are both 0).GWTRNG(long seed)
Constructs this GWTRNG by splitting the given seed across the two parts of state this has withsetState(long)
.GWTRNG(String seed)
Hashesseed
using bothCrossHash.hash(CharSequence)
andString.hashCode()
and uses those two results as the two states withsetState(int, int)
. -
Method Summary
Modifier and Type Method Description GWTRNG
copy()
Creates a copy of this GWTRNG; it will generate the same random numbers, given the same calls in order, as this GWTRNG at the point copy() is called.static long
determine(int state)
A deterministic random long generator that, given one intstate
as input, returns an almost-always-different long as a result.static int
determineBounded(int state, int bound)
A deterministic random int generator that, given one intstate
and an outer intbound
as input, returns an int between 0 (inclusive) andbound
(exclusive) as a result, which should have no noticeable correlation betweenstate
and the result.static double
determineDouble(int state)
A deterministic random double generator that, given one intstate
as input, returns an almost-always-different double between 0.0 and 1.0 as a result.static float
determineFloat(int state)
A deterministic random float generator that, given one intstate
as input, returns an almost-always-different float between 0.0f and 1.0f as a result.static int
determineInt(int state)
A deterministic random int generator that, given one intstate
as input, irreversibly returns an almost-always-different int as a result.boolean
equals(Object o)
long
getState()
Get the current internal state of the StatefulRandomness as a long.int
getStateA()
int
getStateB()
int
hashCode()
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.boolean
nextBoolean()
Get a random bit of state, interpreted as true or false with approximately equal likelihood.double
nextDouble()
Gets a random double between 0.0 inclusive and 1.0 exclusive.float
nextFloat()
Gets a random float between 0.0f inclusive and 1.0f exclusive.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.long
nextLong()
Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).void
setSeed(int seed)
Sets the state of this generator using one int, running it through Zog32RNG's algorithm two times to get two ints.void
setState(int stateA, int stateB)
Sets the current internal state of this GWTRNG with three ints, where stateA and stateB can each be any int unless they are both 0 (which will be treated as if stateA is 1 and stateB is 0).void
setState(long state)
Set the current internal state of this StatefulRandomness with a long.void
setStateA(int stateA)
Sets the first part of the state to the given int.void
setStateB(int stateB)
Sets the second part of the state to the given int.Serializable
toSerializable()
Gets a view of this IRNG in a way that implementsSerializable
, which is simply this IRNG.String
toString()
Methods inherited from class squidpony.squidmath.AbstractRNG
between, between, between, getRandomElement, getRandomElement, getRandomElement, nextDouble, nextFloat, nextLong, nextSignedInt, nextSignedLong, randomOrdering, randomOrdering, randomPortion, shuffle, shuffle, shuffle, shuffle, shuffleInPlace, shuffleInPlace, swap
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
Methods inherited from interface squidpony.squidmath.IRNG
between, between, between, getRandomElement, getRandomElement, getRandomElement, nextDouble, nextFloat, nextLong, nextSignedInt, nextSignedLong, randomOrdering, randomOrdering, randomPortion, shuffle, shuffle, shuffle, shuffle, shuffleInPlace, shuffleInPlace
-
Field Details
-
Constructor Details
-
GWTRNG
public GWTRNG()Creates a new generator seeded using two calls to Math.random(). -
GWTRNG
Constructs this GWTRNG by dispersing the bits of seed usingsetSeed(int)
across the two parts of state this has.- Parameters:
seed
- an int that won't be used exactly, but will affect both components of state
-
GWTRNG
Constructs this GWTRNG by splitting the given seed across the two parts of state this has withsetState(long)
.- Parameters:
seed
- a long that will be split across both components of state
-
GWTRNG
Constructs this GWTRNG by callingsetState(int, int)
on stateA and stateB as given; see that method for the specific details (stateA and stateB are kept as-is unless they are both 0).- Parameters:
stateA
- the number to use as the first part of the state; this will be 1 instead if both seeds are 0stateB
- the number to use as the second part of the state
-
GWTRNG
Hashesseed
using bothCrossHash.hash(CharSequence)
andString.hashCode()
and uses those two results as the two states withsetState(int, int)
. If seed is null, this won't call String.hashCode() on it and will instead use 1 as that state (to avoid the forbidden double-zero case).- Parameters:
seed
- any String; may be null
-
-
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
- Specified by:
next
in classAbstractRNG
- 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).- Specified by:
nextInt
in interfaceIRNG
- Specified by:
nextInt
in classAbstractRNG
- Returns:
- a 32-bit random int.
-
nextInt
Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or negative.- Specified by:
nextInt
in interfaceIRNG
- Overrides:
nextInt
in classAbstractRNG
- Parameters:
bound
- the upper bound (exclusive)- Returns:
- the found number
-
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
- Specified by:
nextLong
in classAbstractRNG
- Returns:
- a 64-bit random long.
-
nextBoolean
Get a random bit of state, interpreted as true or false with approximately equal likelihood. This implementation uses a sign check as a safeguard, since its algorithm is based on (but is not equivalent to) xoroshiro, which recommends a sign check instead of using the least significant bit.- Specified by:
nextBoolean
in interfaceIRNG
- Specified by:
nextBoolean
in classAbstractRNG
- 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 .- Specified by:
nextDouble
in interfaceIRNG
- Specified by:
nextDouble
in classAbstractRNG
- Returns:
- a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive)
-
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 .- Specified by:
nextFloat
in interfaceIRNG
- Specified by:
nextFloat
in classAbstractRNG
- Returns:
- a float between 0f (inclusive) and 0.99999994f (inclusive)
-
copy
Creates a copy of this GWTRNG; it will generate the same random numbers, given the same calls in order, as this GWTRNG at the point copy() is called. The copy will not share references with this GWTRNG.- Specified by:
copy
in interfaceIRNG
- Specified by:
copy
in interfaceRandomnessSource
- Specified by:
copy
in interfaceStatefulRandomness
- Specified by:
copy
in classAbstractRNG
- Returns:
- a copy of this GWTRNG
-
toSerializable
Gets a view of this IRNG in a way that implementsSerializable
, which is simply this IRNG.- Specified by:
toSerializable
in interfaceIRNG
- Specified by:
toSerializable
in classAbstractRNG
- Returns:
- a
Serializable
view of this IRNG or a similar one; alwaysthis
-
setSeed
Sets the state of this generator using one int, running it through Zog32RNG's algorithm two times to get two ints. If the states would both be 0, state A is assigned 1 instead.- Parameters:
seed
- the int to use to produce this generator's state
-
getStateA
-
setStateA
Sets the first part of the state to the given int. As a special case, if the parameter is 0 and stateB is already 0, this will set stateA to 1 instead, since both states cannot be 0 at the same time. Usually, you should usesetState(int, int)
to set both states at once, but the result will be the same if you call setStateA() and then setStateB() or if you call setStateB() and then setStateA().- Parameters:
stateA
- any int
-
getStateB
-
setStateB
Sets the second part of the state to the given int. As a special case, if the parameter is 0 and stateA is already 0, this will set stateA to 1 and stateB to 0, since both cannot be 0 at the same time. Usually, you should usesetState(int, int)
to set both states at once, but the result will be the same if you call setStateA() and then setStateB() or if you call setStateB() and then setStateA().- Parameters:
stateB
- any int
-
setState
Sets the current internal state of this GWTRNG with three ints, where stateA and stateB can each be any int unless they are both 0 (which will be treated as if stateA is 1 and stateB is 0).- Parameters:
stateA
- any int (if stateA and stateB are both 0, this will be treated as 1)stateB
- any int
-
getState
Get the current internal state of the StatefulRandomness as a long.- Specified by:
getState
in interfaceStatefulRandomness
- Returns:
- the current internal state of this object.
-
setState
Set the current internal state of this StatefulRandomness with a long.- Specified by:
setState
in interfaceStatefulRandomness
- Parameters:
state
- a 64-bit long. You should avoid passing 0; this implementation will treat it as 1.
-
equals
-
hashCode
-
toString
-
determineInt
A deterministic random int generator that, given one intstate
as input, irreversibly returns an almost-always-different int as a result. Unlike the rest of GWTRNG, this will not produce all possible ints given all ints as inputs, and probably a third of all possible ints cannot be returned. You should call this withGWTRNG.determineInt(state = state + 1 | 0)
(you can subtract 1 to go backwards instead of forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop.- Parameters:
state
- an int that should go up or down by 1 each call, as withGWTRNG.determineInt(state = state + 1 | 0)
to handle overflow- Returns:
- a not-necessarily-unique int that is usually very different from
state
-
determineBounded
A deterministic random int generator that, given one intstate
and an outer intbound
as input, returns an int between 0 (inclusive) andbound
(exclusive) as a result, which should have no noticeable correlation betweenstate
and the result. You should call this withGWTRNG.determineBound(state = state + 1 | 0, bound)
(you can subtract 1 to go backwards instead of forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop. Like most bounded int generation in SquidLib, this uses some long math, but most of the function uses ints.- Parameters:
state
- an int that should go up or down by 1 each call, as withGWTRNG.determineBounded(state = state + 1 | 0, bound)
to handle overflowbound
- the outer exclusive bound, as an int; may be positive or negative- Returns:
- an int between 0 (inclusive) and
bound
(exclusive)
-
determine
A deterministic random long generator that, given one intstate
as input, returns an almost-always-different long as a result. This can only return a tiny fraction of all possible longs, since there are at most 2 to the 32 possible ints and this doesn't even return different values for each of those. You should call this withGWTRNG.determine(state = state + 1 | 0)
(you can subtract 1 to go backwards instead of forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop.- Parameters:
state
- an int that should go up or down by 1 each call, as withGWTRNG.determine(state = state + 1 | 0)
to handle overflow- Returns:
- a not-necessarily-unique long that is usually very different from
state
-
determineFloat
A deterministic random float generator that, given one intstate
as input, returns an almost-always-different float between 0.0f and 1.0f as a result. Unlike the rest of GWTRNG, this might not produce all possible floats given all ints as inputs, and some fraction of possible floats cannot be returned. You should call this withGWTRNG.determineFloat(state = state + 1 | 0)
(you can subtract 1 to go backwards instead of forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop.- Parameters:
state
- an int that should go up or down by 1 each call, as withGWTRNG.determineFloat(state = state + 1 | 0)
to handle overflow- Returns:
- a not-necessarily-unique float from 0.0f to 1.0f that is usually very different from
state
-
determineDouble
A deterministic random double generator that, given one intstate
as input, returns an almost-always-different double between 0.0 and 1.0 as a result. This cannot produce more than a tiny fraction of all possible doubles because the input is 32 bits and at least 53 bits are needed to represent most doubles from 0.0 to 1.0. You should call this withGWTRNG.determineDouble(state = state + 1 | 0)
(you can subtract 1 to go backwards instead of forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop.- Parameters:
state
- an int that should go up or down by 1 each call, as withGWTRNG.determineDouble(state = state + 1 | 0)
to handle overflow- Returns:
- a not-necessarily-unique double from 0.0 to 1.0 that is usually very different from
state
-