Package squidpony.squidmath
Class SilkRNG
java.lang.Object
squidpony.squidmath.AbstractRNG
squidpony.squidmath.SilkRNG
- All Implemented Interfaces:
 Serializable,IRNG,IStatefulRNG,RandomnessSource,StatefulRandomness
public final class SilkRNG extends AbstractRNG implements IStatefulRNG, Serializable
An IStatefulRNG 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; it is thus like 
Internally, this uses two Weyl sequences (counters with different large increments), and rarely but at specific intervals (when stateA is 0) introduces a lag into one sequence (making stateB keep its value instead of incrementing for one generated number). A multiplier is taken from the upper bits of stateB and multiplied with a xorshifted stateA, then part of a unary hash in the style of SplitMix64 is used to improve quality. A particularly devious piece of bitwise hackery allows this to avoid branching as it decides whether to add the lag or not, and is responsible for this implementation's high speed.
The name comes from spider silk, used in a web, and how this is optimized for Google Web Toolkit.
This was changed on February 29, 2020 to reduce correlation between very similar generators with the same stateA but different stateB; it still passes 32TB of PractRand without anomalies, but may be slightly slower. The reasoning here is that users may want to initialize their RNGs in varied ways, and none of those ways should be unexpectedly flawed. A similar change was applied to TangleRNG, which is much like a 64-bit simplified version of SilkRNG, 4 days later.
Written in 2019 by Tommy Ettinger.
GWTRNG but should perform better on recent desktop JVMs. This uses a
 related algorithm to OrbitRNG, modified to use 32-bit math and more stringently randomize output. It has two
 32-bit ints for state and a period of 0x10000000000000000 (2 to the 64), while passing 32TB of PractRand tests
 without any failures or anomalies (so its quality is very good). It is extremely fast when run on Java 13, at least
 using OpenJ9 as the compiler; it can produce a billion ints a second on moderately-recent laptop hardware. A nice
 quality of the implementation is that it allows any int for both of its states, so you don't need to check and avoid
 setting both states to 0 (which GWTRNG has to do in its internals).
 Internally, this uses two Weyl sequences (counters with different large increments), and rarely but at specific intervals (when stateA is 0) introduces a lag into one sequence (making stateB keep its value instead of incrementing for one generated number). A multiplier is taken from the upper bits of stateB and multiplied with a xorshifted stateA, then part of a unary hash in the style of SplitMix64 is used to improve quality. A particularly devious piece of bitwise hackery allows this to avoid branching as it decides whether to add the lag or not, and is responsible for this implementation's high speed.
The name comes from spider silk, used in a web, and how this is optimized for Google Web Toolkit.
This was changed on February 29, 2020 to reduce correlation between very similar generators with the same stateA but different stateB; it still passes 32TB of PractRand without anomalies, but may be slightly slower. The reasoning here is that users may want to initialize their RNGs in varied ways, and none of those ways should be unexpectedly flawed. A similar change was applied to TangleRNG, which is much like a 64-bit simplified version of SilkRNG, 4 days later.
Written in 2019 by Tommy Ettinger.
- Author:
 - Tommy Ettinger
 - See Also:
 - Serialized Form
 
- 
Field Summary
 - 
Constructor Summary
Constructors Constructor Description SilkRNG()Creates a new generator seeded using two calls to Math.random().SilkRNG(int seed)Constructs this SilkRNG by dispersing the bits of seed usingsetSeed(int)across the two parts of state this has.SilkRNG(int stateA, int stateB)Constructs this SilkRNG by callingsetState(int, int)on stateA and stateB as given; see that method for the specific details (stateA and stateB are kept as-is).SilkRNG(long seed)Constructs this SilkRNG by splitting the given seed across the two parts of state this has withsetState(long).SilkRNG(String seed)Hashesseedusing bothCrossHash.hash(CharSequence)andString.hashCode()and uses those two results as the two states withsetState(int, int). - 
Method Summary
Modifier and Type Method Description SilkRNGcopy()Creates a copy of this SilkRNG; it will generate the same random numbers, given the same calls in order, as this SilkRNG at the point copy() is called.static longdetermine(int state)A deterministic random long generator that, given one intstateas input, returns an almost-always-different long as a result.static intdetermineBounded(int state, int bound)A deterministic random int generator that, given one intstateand an outer intboundas input, returns an int between 0 (inclusive) andbound(exclusive) as a result, which should have no noticeable correlation betweenstateand the result.static doubledetermineDouble(int state)A deterministic random double generator that, given one intstateas input, returns an almost-always-different double between 0.0 and 1.0 as a result.static floatdetermineFloat(int state)A deterministic random float generator that, given one intstateas input, returns an almost-always-different float between 0.0f and 1.0f as a result.static intdetermineInt(int state)A deterministic random int generator that, given one intstateas input, irreversibly returns an almost-always-different int as a result.booleanequals(Object o)longgetState()Get the current internal state of the StatefulRandomness as a long.intgetStateA()intgetStateB()inthashCode()intnext(int bits)Get up to 32 bits (inclusive) of random output; the int this produces will not require more thanbitsbits to represent.booleannextBoolean()Get a random bit of state, interpreted as true or false with approximately equal likelihood.doublenextDouble()Gets a random double between 0.0 inclusive and 1.0 exclusive.floatnextFloat()Gets a random float between 0.0f inclusive and 1.0f exclusive.intnextInt()Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive).intnextInt(int bound)Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or negative.longnextLong()Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).voidsetSeed(int seed)Sets the state of this generator using one int, running it through Zog32RNG's algorithm two times to get two ints.voidsetState(int stateA, int stateB)Sets the current internal state of this SilkRNG with two ints, where stateA and stateB can each be any int.voidsetState(long state)Set the current internal state of this StatefulRandomness with a long.voidsetStateA(int stateA)Sets the first part of the state to the given int.voidsetStateB(int stateB)Sets the second part of the state to the given int.SerializabletoSerializable()Gets a view of this IRNG in a way that implementsSerializable, which is simply this IRNG.StringtoString()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, swapMethods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, waitMethods 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
- 
SilkRNG
public SilkRNG()Creates a new generator seeded using two calls to Math.random(). - 
SilkRNG
Constructs this SilkRNG 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
 - 
SilkRNG
Constructs this SilkRNG 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
 - 
SilkRNG
Constructs this SilkRNG by callingsetState(int, int)on stateA and stateB as given; see that method for the specific details (stateA and stateB are kept as-is).- Parameters:
 stateA- the number to use as the first part of the statestateB- the number to use as the second part of the state
 - 
SilkRNG
Hashesseedusing 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 0 as that state.- 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 thanbitsbits to represent.- Specified by:
 nextin interfaceIRNG- Specified by:
 nextin interfaceRandomnessSource- Specified by:
 nextin 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:
 nextIntin interfaceIRNG- Specified by:
 nextIntin 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:
 nextIntin interfaceIRNG- Overrides:
 nextIntin 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:
 nextLongin interfaceIRNG- Specified by:
 nextLongin interfaceRandomnessSource- Specified by:
 nextLongin 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 an optimization.- Specified by:
 nextBooleanin interfaceIRNG- Specified by:
 nextBooleanin 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:
 nextDoublein interfaceIRNG- Specified by:
 nextDoublein 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:
 nextFloatin interfaceIRNG- Specified by:
 nextFloatin classAbstractRNG- Returns:
 - a float between 0f (inclusive) and 0.99999994f (inclusive)
 
 - 
copy
Creates a copy of this SilkRNG; it will generate the same random numbers, given the same calls in order, as this SilkRNG at the point copy() is called. The copy will not share references with this SilkRNG.- Specified by:
 copyin interfaceIRNG- Specified by:
 copyin interfaceRandomnessSource- Specified by:
 copyin interfaceStatefulRandomness- Specified by:
 copyin classAbstractRNG- Returns:
 - a copy of this SilkRNG
 
 - 
toSerializable
Gets a view of this IRNG in a way that implementsSerializable, which is simply this IRNG.- Specified by:
 toSerializablein interfaceIRNG- Specified by:
 toSerializablein classAbstractRNG- Returns:
 - a 
Serializableview 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.- Parameters:
 stateA- any int
 - 
getStateB
 - 
setStateB
Sets the second part of the state to the given int.- Parameters:
 stateB- any int
 - 
setState
Sets the current internal state of this SilkRNG with two ints, where stateA and stateB can each be any int.- Parameters:
 stateA- any intstateB- any int
 - 
getState
Get the current internal state of the StatefulRandomness as a long.- Specified by:
 getStatein interfaceStatefulRandomness- Returns:
 - the current internal state of this object.
 
 - 
setState
Set the current internal state of this StatefulRandomness with a long.- Specified by:
 setStatein 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 intstateas input, irreversibly returns an almost-always-different int as a result. Unlike the rest of SilkRNG, 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 withSilkRNG.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 withSilkRNG.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 intstateand an outer intboundas input, returns an int between 0 (inclusive) andbound(exclusive) as a result, which should have no noticeable correlation betweenstateand the result. You should call this withSilkRNG.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 withSilkRNG.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 intstateas 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 withSilkRNG.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 withSilkRNG.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 intstateas input, returns an almost-always-different float between 0.0f and 1.0f as a result. Unlike the rest of SilkRNG, 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 withSilkRNG.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 withSilkRNG.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 intstateas 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 withSilkRNG.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 withSilkRNG.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 
 
 -