XorShift128.java

/*
 * License : The MIT License
 * Copyright(c) 2021 Olyutorskii
 */

package io.github.olyutorskii.aletojio.rng.xorsft;

import io.github.olyutorskii.aletojio.rng.RndInt32;

/**
 * xorshift (128bit) Pseudo Random Generator.
 *
 * <p>Warning: The default seed value will give a very biased result.
 *
 * @see <a href="https://en.wikipedia.org/wiki/Xorshift">Xorshift (Wikipedia)</a>
 * @see <a href="https://www.jstatsoft.org/article/view/v008i14">Xorshift RNGs</a>
 */
public class XorShift128 implements RndInt32 {

    // [5, 14, 1], [15, 4, 21], [23, 24, 3], [5, 12, 29]
    private static final int LSF_0 =  5;
    private static final int RSF_0 = 12;
    private static final int RSF_1 = 29;

    private static final String MSG_ILLSEED = "At least one seed must be non-zero";


    private int s0 = 1;
    private int s1 = 0;
    private int s2 = 0;
    private int s3 = 0;


    /**
     * Constructor.
     *
     * <p>Warning: The default seed value will give a very biased result.
     */
    public XorShift128() {
        super();
        return;
    }


    /**
     * {@inheritDoc}
     *
     * @return {@inheritDoc}
     */
    @Override
    public int nextInt32() {
        int tmp0 = this.s0;
        int tmp3 = this.s3;

        tmp0 = tmp0 ^ (tmp0 <<  LSF_0);
        tmp0 = tmp0 ^ (tmp0 >>> RSF_0);
        tmp3 = tmp3 ^ (tmp3 >>> RSF_1);

        final int result = tmp0 ^ tmp3;

        this.s0 = this.s1;
        this.s1 = this.s2;
        this.s2 = this.s3;
        this.s3 = result;

        return result;
    }

    /**
     * Set seed.
     *
     * <p>At least one seed must be non-zero.
     *
     * @param s0Arg seed0
     * @param s1Arg seed1
     * @param s2Arg seed2
     * @param s3Arg seed3
     * @throws IllegalArgumentException At least one seed must be non-zero
     */
    public void setSeed(int s0Arg, int s1Arg, int s2Arg, int s3Arg)
            throws IllegalArgumentException {
        if ((s0Arg | s1Arg | s2Arg | s3Arg) == 0L) {
            throw new IllegalArgumentException(MSG_ILLSEED);
        }

        this.s0 = s0Arg;
        this.s1 = s1Arg;
        this.s2 = s2Arg;
        this.s3 = s3Arg;

        return;
    }

}