Package squidpony.squidmath
Class PintRNG
java.lang.Object
squidpony.squidmath.PintRNG
- All Implemented Interfaces:
Serializable
,RandomnessSource
,StatefulRandomness
public final class PintRNG extends Object implements RandomnessSource, StatefulRandomness, Serializable
A RandomnessSource based on PCG-Random that has a single int of state. Its period is extremely short at 2 to the 32,
but its quality over that period is high even though its speed is not especially noteworthy. This generator is not
suitable for GWT; for that you should use
Quality should be excellent in this version (at least for a generator with so little state) since it's based directly on PCG-Random's choices of numerical constants. Visual tests, at least, appear indistinguishable from other PRNGs. Period is very low, at 2 to the 32, but all seeds should be valid, including 0. Generating 64 bits of random data takes a little less than twice as much time as generating 32 bits, since this can avoid some overhead via inlining.
The name can be construed as Pint-Size, since this has a small period and uses a smaller amount of space, or as Permuted Int, since this is based on PermutedRNG, changed to use 32-bit operations on ints.
Based on work by Melissa E. O'Neill for PCG-Random; some code has been ported more-directly than other sections, but the foundation for this class would not be possible without O'Neill's work.
Created by Tommy Ettinger on 11/15/2016.
Starfish32RNG
or its wrapper GWTRNG
if you need a
StatefulRandomness, Lathe32RNG
if you want optimal speed and don't mind distribution flaws when producing
longs, or Oriole32RNG
or XoshiroStarPhi32RNG
if you need a higher period but don't need
StatefulRandomness' state adjustment methods.
Quality should be excellent in this version (at least for a generator with so little state) since it's based directly on PCG-Random's choices of numerical constants. Visual tests, at least, appear indistinguishable from other PRNGs. Period is very low, at 2 to the 32, but all seeds should be valid, including 0. Generating 64 bits of random data takes a little less than twice as much time as generating 32 bits, since this can avoid some overhead via inlining.
The name can be construed as Pint-Size, since this has a small period and uses a smaller amount of space, or as Permuted Int, since this is based on PermutedRNG, changed to use 32-bit operations on ints.
Based on work by Melissa E. O'Neill for PCG-Random; some code has been ported more-directly than other sections, but the foundation for this class would not be possible without O'Neill's work.
Created by Tommy Ettinger on 11/15/2016.
- See Also:
- Serialized Form
-
Field Summary
Fields Modifier and Type Field Description int
state
-
Constructor Summary
-
Method Summary
Modifier and Type Method Description PintRNG
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 int
determine(int state)
Gets a pseudo-random int that is a permutation ofstate
, which is an int.static int
determine(int a, int b)
static int
determineBounded(int state, int bound)
static int
disperse(int state)
Likedetermine(int)
, gets a pseudo-random int that is a permutation ofstate
, which is an int.static int
disperseBounded(int state, int bound)
boolean
equals(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 upper bound.int
nextInt(int lower, int upper)
Inclusive lower, exclusive upper.long
nextLong()
Can return any long, positive or negative, of any size permissible in a 64-bit signed integer.void
setState(long seed)
Sets the current state of this generator (an int) using only the least-significant 32 bits of seed (by casting a mask of those bits in seed to int, which helps ensure that a full 32 bits of state are possible).int
skip(int advance)
Advances or rolls back the PintRNG's state without actually generating each number.String
toString()
-
Field Details
-
Constructor Details
-
Method Details
-
next
Description copied from interface:RandomnessSource
Using this method, any algorithm that might use the built-in Java Random can interface with this randomness source.- Specified by:
next
in interfaceRandomnessSource
- Parameters:
bits
- the number of bits to be returned- Returns:
- the integer containing the appropriate number of bits
-
nextInt
Can return any int, positive or negative, of any size permissible in a 32-bit signed integer.- Returns:
- any int, all 32 bits are random
-
nextLong
Can return any long, positive or negative, of any size permissible in a 64-bit signed integer. Internally, generates two random 32-bit values and combines them into one random long.- Specified by:
nextLong
in interfaceRandomnessSource
- Returns:
- any long, all 64 bits are random
-
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. 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
- Specified by:
copy
in interfaceStatefulRandomness
- Returns:
- a copy of this RandomnessSource
-
nextInt
Exclusive on the upper bound. The lower bound is 0.
Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/- Parameters:
bound
- the upper bound; should be positive- Returns:
- a random int less than n and at least equal to 0
-
nextInt
Inclusive lower, exclusive upper.- Parameters:
lower
- the lower bound, inclusive, can be positive or negativeupper
- the upper bound, exclusive, should be positive, must be greater than lower- Returns:
- a random int at least equal to lower and less than upper
-
nextDouble
Gets a uniform random double in the range [0.0,1.0)- Returns:
- a random double at least equal to 0.0 and less than 1.0
-
nextDouble
Gets a uniform random double in the range [0.0,outer) given a positive parameter outer. If outer is negative, it will be the (exclusive) lower bound and 0.0 will be the (inclusive) upper bound.- Parameters:
outer
- the exclusive outer bound, can be negative- Returns:
- a random double between 0.0 (inclusive) and outer (exclusive)
-
nextFloat
Gets a uniform random float in the range [0.0,1.0)- Returns:
- a random float at least equal to 0.0 and less than 1.0
-
nextBoolean
Gets a random value, true or false. Calls nextInt() once.- Returns:
- a random true or false value.
-
nextBytes
Given a byte array as a parameter, this will fill the array with random bytes (modifying it in-place). Calls nextInt()Math.ceil(bytes.length / 4.0)
times.- Parameters:
bytes
- a byte array that will have its contents overwritten with random bytes.
-
setState
Sets the current state of this generator (an int) using only the least-significant 32 bits of seed (by casting a mask of those bits in seed to int, which helps ensure that a full 32 bits of state are possible). Giving int seeds should set the seed to an identical int; long seeds will lose any information in higher bits (including the sign, so 0xFFFFFFFF00000000L, which is a negative long, would be treated as 0 since only the 0x00000000 part at the end is actually used).- Specified by:
setState
in interfaceStatefulRandomness
- Parameters:
seed
- the seed to use for this PintRNG, as if it was constructed with this seed.
-
getState
Gets the current state of this generator.- Specified by:
getState
in interfaceStatefulRandomness
- Returns:
- the current seed of this PintRNG, changed once per call to nextInt()
-
toString
-
equals
-
hashCode
-
skip
Advances or rolls back the PintRNG's state without actually generating each number. Skip forward or backward a number of steps specified by advance, where a step is equal to one call to nextInt(), and returns the random number produced at that step (you can get the state withgetState()
).
The method used here is based on Brown, "Random Number Generation with Arbitrary Stride,", Transactions of the American Nuclear Society (Nov. 1994). The code is mostly the same as in PCG-Random's C port by M.E. O'Neill, specifically this file. Skipping ahead or behind takes more than constant time, unlike withLightRNG
, but less time than calling nextInt()advance
times. Skipping backwards by one step is the worst case for this.- Parameters:
advance
- Number of future generations to skip past. Can be negative to backtrack.- Returns:
- the int that would be generated after generating advance random numbers.
-
determine
Gets a pseudo-random int that is a permutation ofstate
, which is an int. This should normally be called with a technique likePintRNG.determine(state = state * 0x2C9277B5 + 0xAC564B05)
, where 0xAC564B05 can be changed to any odd constant as long as it is the same across calls to this. You can effectively produce multiple uncorrelated streams by adding different constants in place of 0xAC564B05, applied to different states.- Parameters:
state
- any int, but should be updated likestate = state * 0x2C9277B5 + 0xAC564B05
, where 0xAC564B05 can be any odd-number constant- Returns:
- any int, pseudo-randomly obtained from state
-
disperse
Likedetermine(int)
, gets a pseudo-random int that is a permutation ofstate
, which is an int. Unlike determine(), this static method performs an extra step to avoid correlation between similar inputs, such as 4, 5, and 6, and their outputs. If you already give very distant numbers as subsequent inputs to determine(), then you should continue to use that method unless you discover issues with correlation; otherwise it's not a bad idea to default to this method, though it is somewhat slower than determine(). This method is safe to use with sequential ints, so you can call it with the techniquePintRNG.disperse(++state)
, or just use it on int data as you obtain it to randomize its values.- Parameters:
state
- any int- Returns:
- any int, pseudo-randomly obtained from state
-
determine
-
determineBounded
-
disperseBounded
-