DX120Generator.java
package nl.tudelft.simulation.jstats.streams;
/**
* The DX-120-4 pseudo random number generator. This generator is described in
* <a href="http://www.cs.memphis.edu/~dengl/dx-rng/dengxu2002.pdf"> A System of High-dimensional, Efficient, Long-cycle and
* Portable Uniform Random Number Generators </a>.
* <p>
* Copyright (c) 2002-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL
* project is distributed under a three-clause BSD-style license, which can be found at
* <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">
* https://https://simulation.tudelft.nl/dsol/docs/latest/license.html</a>.
* </p>
* @author <a href="https://www.tudelft.nl/averbraeck" target="_blank"> Alexander Verbraeck</a>
* @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
*/
public class DX120Generator extends RandomNumberGenerator
{
/** */
private static final long serialVersionUID = 20150426L;
/** the k value of the DX-120 Generator. */
private static final int K = 120;
/** the mask value 2^31-1 (or 1 << 31)-1. */
private static final long MASK = Long.MAX_VALUE;
/** the LCG multiplier. */
private static final long MULTIPLIER = 16807;
/** the buffer for this generator. */
private long[] buffer = null;
/** indexing attributes. */
private int index;
/** indexing attributes. */
private int k13;
/** indexing attributes. */
private int k23;
/**
* constructs a new LC48Generator. the seed value used equals System.currentTimeMillis()
*/
public DX120Generator()
{
this(System.currentTimeMillis());
}
/**
* constructs a new LC48Generator.
* @param seed long; the seed
*/
public DX120Generator(final long seed)
{
super(seed);
this.initialize();
}
/**
* initializes the generator.
*/
private void initialize()
{
this.buffer = new long[DX120Generator.K];
this.buffer[0] = super.seed & MASK;
if (this.buffer[0] == 0)
{
// super.seed=Integer.MAXValue --> seed & UMASK==0
// We set the seed again and enforce a different value.
this.setSeed(System.currentTimeMillis());
}
if (this.buffer[0] < 0)
{
this.buffer[0] = Math.abs(this.buffer[0] - 1);
}
for (int i = 1; i < K; i++)
{
this.buffer[i] = (MULTIPLIER * this.buffer[i - 1]) & MASK;
}
this.index = K - 1; /* running index */
this.k13 = K / 3 - 1; // (k13 = 39)
this.k23 = 2 * K / 3 - 1; // (k23 = 79)
}
/** {@inheritDoc} */
@Override
public synchronized long next(final int bits)
{
// u_dx4 (BB4) variant of http://www.cs.memphis.edu/~dengl/dx-rng/dx-120.c
// note that the DX120 RNG provides 31 bits max.
if (bits > 63)
{
throw new IllegalArgumentException("bits (" + bits + ") not in range [0,63]");
}
int tempIndex = this.index;
if (++this.index >= K)
{
this.index = 0; /* wrap around running index */
}
if (++this.k13 >= K)
{
this.k13 = 0; /* wrap around k13 */
}
if (++this.k23 >= K)
{
this.k23 = 0; /* wrap around running k23 */
}
this.buffer[this.index] =
(521673 * (this.buffer[this.index] + this.buffer[this.k13] + this.buffer[this.k23] + this.buffer[tempIndex]))
& MASK;
return (this.buffer[this.index]) >>> (63 - bits);
}
/** {@inheritDoc} */
@Override
public synchronized void setSeed(final long seed)
{
this.seed = seed;
this.initialize();
}
}