public class DiverRNG extends java.lang.Object implements StatefulRandomness, java.io.Serializable
state = (state ^ 7822362180758744021) * -4126379630918251389
, and the only requirements for an XLCG are that
the constant used with XOR, when treated as unsigned and modulo 8, equals 5, while the multiplier, again treated as
unsigned and modulo 8, equals 3). Starting with that XLCG's output, it bitwise-left-rotates by 27, multiplies by a
very large negative long (see next), then returns a right-xorshift by 25. The large negative long is
-2643881736870682267, which when treated as unsigned is 2 to the 64 divided by an irrational number that generalizes
the golden ratio. This specific irrational number is the solution to x
5
= x + 1
.
Other multipliers also seem to work well as long as they have enough set bits (fairly-small multipliers fail tests).
For whatever reason, the output of this simple function passes all 32TB of PractRand with one anomaly ("unusual"
at 256GB), meaning its statistical quality is excellent. ThrustAltRNG
is slightly faster, but isn't
equidistributed; unlike ThrustAltRNG, this can produce all long values as output. ThrustAltRNG bunches some outputs
and makes producing them more likely, while others can't be produced at all. Notably, this generator is faster than
LinnormRNG
, which it is based on, while improving its quality, is faster than LightRNG
while keeping
the same or higher quality, and is also faster than XoRoRNG
while passing tests that XoRoRNG always or
frequently fails, such as binary matrix rank tests.
nextLong()
.
nextLong()
and
similar instance methods here; they're a little faster than LinnormRNG.determine(long)
and its family while
actually having much better stability in case an increment is a poor fit for the internals of the generator. Like
nextLong()
, determine(long)
can produce all possible long outputs and can take any long input;
among determine() methods in this library that satisfy that constraint on input and output, this class' appears to be
the fastest.
Constructor and Description |
---|
DiverRNG()
Creates a new generator seeded using Math.random.
|
DiverRNG(long seed) |
DiverRNG(java.lang.String seed) |
Modifier and Type | Method and Description |
---|---|
DiverRNG |
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.
|
static long |
determine(long state)
Fast static randomizing method that takes its state as a parameter; state is expected to change between calls to
this.
|
static int |
determineBounded(long state,
int bound)
Fast static randomizing method that takes its state as a parameter and limits output to an int between 0
(inclusive) and bound (exclusive); state is expected to change between calls to this.
|
static double |
determineDouble(long state)
Returns a random double that is deterministic based on state; if state is the same on two calls to this, this
will return the same float.
|
static float |
determineFloat(long state)
Returns a random float that is deterministic based on state; if state is the same on two calls to this, this will
return the same float.
|
boolean |
equals(java.lang.Object o) |
long |
getState()
Gets the current state of this generator.
|
int |
hashCode() |
int |
next(int bits)
Using this method, any algorithm that might use the built-in Java Random
can interface with this randomness source.
|
boolean |
nextBoolean()
Gets a random value, true or false.
|
void |
nextBytes(byte[] bytes)
Given a byte array as a parameter, this will fill the array with random bytes (modifying it
in-place).
|
double |
nextDouble()
Gets a uniform random double in the range [0.0,1.0)
|
double |
nextDouble(double outer)
Gets a uniform random double in the range [0.0,outer) given a positive parameter outer.
|
float |
nextFloat()
Gets a uniform random float in the range [0.0,1.0)
|
int |
nextInt()
Can return any int, positive or negative, of any size permissible in a 32-bit signed integer.
|
int |
nextInt(int bound)
Exclusive on the outer bound.
|
int |
nextInt(int inner,
int outer)
Inclusive inner, exclusive outer.
|
long |
nextLong()
Can return any long, positive or negative, of any size permissible in a 64-bit signed integer.
|
long |
nextLong(long bound)
Exclusive on bound (which may be positive or negative), with an inner bound of 0.
|
long |
nextLong(long lower,
long upper)
Inclusive inner, exclusive outer; lower and upper can be positive or negative and there's no requirement for one
to be greater than or less than the other.
|
static long |
randomize(long state)
High-quality static randomizing method that takes its state as a parameter; state is expected to change between
calls to this.
|
static int |
randomizeBounded(long state,
int bound)
High-quality static randomizing method that takes its state as a parameter and limits output to an int between 0
(inclusive) and bound (exclusive); state is expected to change between calls to this.
|
static double |
randomizeDouble(long state)
Returns a random double that is deterministic based on state; if state is the same on two calls to this, this
will return the same float.
|
static float |
randomizeFloat(long state)
Returns a random float that is deterministic based on state; if state is the same on two calls to this, this will
return the same float.
|
void |
setState(long seed)
Sets the seed (also the current state) of this generator.
|
java.lang.String |
toString() |
public DiverRNG()
public DiverRNG(long seed)
public DiverRNG(java.lang.String seed)
public int next(int bits)
RandomnessSource
next
in interface RandomnessSource
bits
- the number of bits to be returnedpublic long nextLong()
nextLong
in interface RandomnessSource
public DiverRNG copy()
copy
in interface RandomnessSource
copy
in interface StatefulRandomness
public int nextInt()
public int nextInt(int bound)
IRNG.nextSignedInt(int)
if you need a negative outer bound.bound
- the upper bound; should be positivepublic int nextInt(int inner, int outer)
inner
- the inner bound, inclusive, can be positive or negativeouter
- the outer bound, exclusive, can be positive or negative, should be greater than innerpublic long nextLong(long bound)
nextLong()
.bound
- the outer exclusive bound; can be positive or negativepublic long nextLong(long lower, long upper)
lower
- the lower bound, inclusive, can be positive or negativeupper
- the upper bound, exclusive, can be positive or negativepublic double nextDouble()
public double nextDouble(double outer)
outer
- the exclusive outer bound, can be negativepublic float nextFloat()
public boolean nextBoolean()
public void nextBytes(byte[] bytes)
Math.ceil(bytes.length / 8.0)
times.bytes
- a byte array that will have its contents overwritten with random bytes.public void setState(long seed)
setState
in interface StatefulRandomness
seed
- the seed to use for this LightRNG, as if it was constructed with this seed.public long getState()
getState
in interface StatefulRandomness
public java.lang.String toString()
toString
in class java.lang.Object
public boolean equals(java.lang.Object o)
equals
in class java.lang.Object
public int hashCode()
hashCode
in class java.lang.Object
public static long determine(long state)
DiverRNG.determine(++state)
or DiverRNG.determine(--state)
to produce a sequence of different numbers, and you may have slightly worse quality with increments or decrements
other than 1. All longs are accepted by this method, and all longs can be produced; unlike several other classes'
determine() methods, passing 0 here does not return 0.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- any long; subsequent calls should change by an odd number, such as with ++state
public static long randomize(long state)
DiverRNG.randomize(++state)
or
DiverRNG.randomize(--state)
to produce a sequence of different numbers, but any increments are allowed
(even-number increments won't be able to produce all outputs, but their quality will be fine for the numbers they
can produce). All longs are accepted by this method, and all longs can be produced; unlike several other classes'
determine() methods, passing 0 here does not return 0.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- any long; subsequent calls should change by an odd number, such as with ++state
public static int determineBounded(long state, int bound)
DiverRNG.determineBounded(++state, bound)
or DiverRNG.determineBounded(--state, bound)
to
produce a sequence of different numbers. All longs are accepted
by this method, but not all ints between 0 and bound are guaranteed to be produced with equal likelihood (for any
odd-number values for bound, this isn't possible for most generators). The bound can be negative.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- any long; subsequent calls should change by an odd number, such as with ++state
bound
- the outer exclusive bound, as an intpublic static int randomizeBounded(long state, int bound)
DiverRNG.randomizeBounded(++state)
or DiverRNG.randomize(--state)
to produce a sequence of
different numbers, but any increments are allowed (even-number increments won't be able to produce all outputs,
but their quality will be fine for the numbers they can produce). All longs are accepted by this method, but not
all ints between 0 and bound are guaranteed to be produced with equal likelihood (for any odd-number values for
bound, this isn't possible for most generators). The bound can be negative.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- any long; subsequent calls should change by an odd number, such as with ++state
bound
- the outer exclusive bound, as an intpublic static float determineFloat(long state)
determineFloat(++state)
, where the increment for state should generally be 1. The period is 2 to the 64
if you increment or decrement by 1, but there are only 2 to the 30 possible floats between 0 and 1.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- a variable that should be different every time you want a different random result;
using determineFloat(++state)
is recommended to go forwards or
determineFloat(--state)
to generate numbers in reverse orderstate
public static float randomizeFloat(long state)
randomizeFloat(++state)
, where the increment for state can be any value and should usually be odd
(even-number increments reduce the period). The period is 2 to the 64 if you increment or decrement by any odd
number, but there are only 2 to the 30 possible floats between 0 and 1.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- a variable that should be different every time you want a different random result;
using randomizeFloat(++state)
is recommended to go forwards or
randomizeFloat(--state)
to generate numbers in reverse orderstate
public static double determineDouble(long state)
determineDouble(++state)
, where the increment for state should generally be 1. The period is 2 to the 64
if you increment or decrement by 1, but there are only 2 to the 62 possible doubles between 0 and 1.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- a variable that should be different every time you want a different random result;
using determineDouble(++state)
is recommended to go forwards or
determineDouble(--state)
to generate numbers in reverse orderstate
public static double randomizeDouble(long state)
randomizeDouble(++state)
, where the increment for state can be any number but should usually be odd
(even-number increments reduce the period). The period is 2 to the 64 if you increment or decrement by 1, but
there are only 2 to the 62 possible doubles between 0 and 1.
determine()
is the same as
LinnormRNG.determine(long)
and will behave well when the inputs are sequential, while randomize()
is a completely different algorithm based on Pelle Evensen's rrxmrrxmsx_0 and evaluated with
the same
testing requirements Evensen used for rrxmrrxmsx_0; it will have excellent quality regardless of patterns in
input but will be about 30% slower than determine()
. Each method will produce all long outputs if given
all possible longs as input.state
- a variable that should be different every time you want a different random result;
using randomizeDouble(++state)
is recommended to go forwards or
randomizeDouble(--state)
to generate numbers in reverse orderstate
Copyright © Eben Howard 2012–2022. All rights reserved.