RandomNumberGenerator.java

package nl.tudelft.simulation.jstats.streams;

import nl.tudelft.simulation.language.DsolException;
import nl.tudelft.simulation.language.reflection.StateSaver;

/**
 * The RandomNumberGenerator class provides an abstract basis for all pseudo random number generators.
 * <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 abstract class RandomNumberGenerator implements StreamInterface
{
    /** */
    private static final long serialVersionUID = 20150426L;

    /** The seed of the generator. */
    @SuppressWarnings("checkstyle:visibilitymodifier")
    protected long seed;

    /** The original seed of the generator. */
    private final long originalSeed;

    /**
     * Construct a new RandomNumberGenerator. The seed value used in the rng is set to System.currentTimeMillis();
     */
    public RandomNumberGenerator()
    {
        this(System.currentTimeMillis());
    }

    /**
     * Construct a new RandomNumberGenerator.
     * @param seed long; the seed of the generator.
     */
    public RandomNumberGenerator(final long seed)
    {
        if (seed <= 0)
        {
            throw new IllegalArgumentException("seed(" + seed + ")<=0");
        }
        this.setSeed(seed);
        this.originalSeed = seed;
    }

    /** {@inheritDoc} */
    @Override
    public void reset()
    {
        this.setSeed(this.seed);
    }

    /**
     * returns the next value in the stream.
     * @param bits int; the number of bits used
     * @return the next value.
     */
    protected abstract long next(int bits);

    /** {@inheritDoc} */
    @Override
    public boolean nextBoolean()
    {
        return next(1) != 0;
    }

    /** {@inheritDoc} */
    @Override
    public double nextDouble()
    {
        long l = ((next(26)) << 27) + next(27);
        return l / (double) (1L << 53);
    }

    /** {@inheritDoc} */
    @Override
    public float nextFloat()
    {
        int i = (int) this.next(24);
        return i / ((float) (1 << 24));
    }

    /** {@inheritDoc} */
    @Override
    public int nextInt()
    {
        return (int) this.next(32);
    }

    /** {@inheritDoc} */
    @Override
    public synchronized int nextInt(final int i, final int j)
    {
        if (i < 0 || j <= 0 || i >= j)
        {
            throw new IllegalArgumentException("i, j must be positive");
        }
        return i + (int) Math.floor((j - i + 1) * this.nextDouble());
    }

    /** {@inheritDoc} */
    @Override
    public long nextLong()
    {
        return ((next(32)) << 32) + next(32);
    }

    /** {@inheritDoc} */
    @Override
    public abstract void setSeed(long seed);

    /** {@inheritDoc} */
    @Override
    public long getSeed()
    {
        return this.seed;
    }

    /** {@inheritDoc} */
    @Override
    public long getOriginalSeed()
    {
        return this.originalSeed;
    }

    /** {@inheritDoc} */
    @Override
    public String toString()
    {
        return this.getClass().toString() + "[" + this.seed + "]";
    }

    /** {@inheritDoc} */
    @Override
    public byte[] saveState() throws StreamException
    {
        try
        {
            return StateSaver.saveState(this);
        }
        catch (DsolException exception)
        {
            throw new StreamException(exception);
        }
    }

    /** {@inheritDoc} */
    @Override
    public void restoreState(final byte[] state) throws StreamException
    {
        try
        {
            StateSaver.restoreState(this, state);
        }
        catch (DsolException exception)
        {
            throw new StreamException(exception);
        }
    }

}