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 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

    Constructors 
    Constructor Description
    PintRNG()
    Creates a new generator seeded using Math.random.
    PintRNG​(int a)  
    PintRNG​(long seed)  
  • 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 of state, which is an int.
    static int determine​(int a, int b)  
    static int determineBounded​(int state, int bound)  
    static int disperse​(int state)
    Like determine(int), gets a pseudo-random int that is a permutation of state, 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()  

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Field Details

  • Constructor Details

  • Method Details

    • next

      public int next​(int bits)
      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 interface RandomnessSource
      Parameters:
      bits - the number of bits to be returned
      Returns:
      the integer containing the appropriate number of bits
    • nextInt

      public int 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

      public long 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 interface RandomnessSource
      Returns:
      any long, all 64 bits are random
    • copy

      public 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. 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 interface RandomnessSource
      Specified by:
      copy in interface StatefulRandomness
      Returns:
      a copy of this RandomnessSource
    • nextInt

      public int nextInt​(int bound)
      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

      public int nextInt​(int lower, int upper)
      Inclusive lower, exclusive upper.
      Parameters:
      lower - the lower bound, inclusive, can be positive or negative
      upper - 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

      public double 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

      public double nextDouble​(double outer)
      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

      public float 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

      public boolean nextBoolean()
      Gets a random value, true or false. Calls nextInt() once.
      Returns:
      a random true or false value.
    • nextBytes

      public void nextBytes​(byte[] bytes)
      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

      public 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). 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 interface StatefulRandomness
      Parameters:
      seed - the seed to use for this PintRNG, as if it was constructed with this seed.
    • getState

      public long getState()
      Gets the current state of this generator.
      Specified by:
      getState in interface StatefulRandomness
      Returns:
      the current seed of this PintRNG, changed once per call to nextInt()
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • equals

      public boolean equals​(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • skip

      public int skip​(int advance)
      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 with getState()).
      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 with LightRNG, 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

      public static int determine​(int state)
      Gets a pseudo-random int that is a permutation of state, which is an int. This should normally be called with a technique like PintRNG.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 like state = state * 0x2C9277B5 + 0xAC564B05, where 0xAC564B05 can be any odd-number constant
      Returns:
      any int, pseudo-randomly obtained from state
    • disperse

      public static int disperse​(int state)
      Like determine(int), gets a pseudo-random int that is a permutation of state, 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 technique PintRNG.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

      public static int determine​(int a, int b)
    • determineBounded

      public static int determineBounded​(int state, int bound)
    • disperseBounded

      public static int disperseBounded​(int state, int bound)