Cmwc.java

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

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

/**
 * Complementary-multiply-with-carry random number generator.
 *
 * <p>Random sequence X(n) is derived as follows with parameter a(multiplier), b(divisor).
 * <ul>
 * <li>{@code T(n) = a * X(n-r) + C(n-1)}
 * <li>{@code C(n) = T(n) / b}
 * <li>{@code Y(n) = T(n) mod b}
 * <li>{@code X(n) = b - 1 - Y(n)}
 * </ul>
 *
 * <p>r is the length of the record that stores past results.
 * "carry" comes from C(n-1).
 *
 * @see <a href="https://en.wikipedia.org/wiki/Multiply-with-carry_pseudorandom_number_generator">
 * Multiply-with-carry pseudorandom number generator (Wikipedia)
 * </a>
 */
public class Cmwc extends Mwc {

    private static final int  DEF_RECORDS    = 1024;
    private static final long DEF_MULTIPLIER = 987769338L;
    private static final long DEF_DIVISOR    = (1L << 32) - 1L;


    private final long minuend;


    /**
     * Constructor.
     *
     * <ul>
     * <li>record length must be greater than 0.
     * <li>multiplier must be greater than 1.
     * <li>divisor must be greater than 1.
     * </ul>
     *
     * <p>If you want 32-bit uniformly distributed random numbers,
     * the divisor must be 2**32, but you can compromise with 2**32 -1.
     *
     * @param recLen records length
     * @param mulArg multiplier
     * @param divArg divisor
     * @throws IllegalArgumentException illegal argument
     */
    public Cmwc(int recLen, long mulArg, long divArg) throws IllegalArgumentException {
        super(recLen, mulArg, divArg);
        this.minuend = divArg - 1;
        return;
    }

    /**
     * Constructor.
     *
     * <ul>
     * <li>Default record length = 1024
     * <li>Default multiplier value = 987769338
     * <li>Default divisor value = 2**32 - 1
     * </ul>
     *
     * <p>* Caution : If you don't provide your entropy to seeds,
     * it takes over million trials until the seed is scrambled.
     *
     * @throws IllegalArgumentException illegal argument
     * @see <a href="http://digitalcommons.wayne.edu/cgi/viewcontent.cgi?article=1725&context=jmasm">
     * Random Number Generators
     * </a>
     */
    public Cmwc() throws IllegalArgumentException {
        this(DEF_RECORDS, DEF_MULTIPLIER, DEF_DIVISOR);
        // this(4, 987654978L, (1L << 32) - 1L);
        // this(8, 987651670L, (1L << 32) - 1L);
        // this(2048, 1047570L, (1L << 32) - 1L);
        // this(4096, 18782L, (1L << 32) - 1L);
        // this(42658, 15455296L, 1L << 32);
        return;
    }


    /**
     * {@inheritDoc}
     *
     * @param tVal {@inheritDoc}
     * @return {@inheritDoc}
     */
    @Override
    protected int funcRndFromTval(long tVal) {
        long lVal = this.minuend - super.funcRndFromTval(tVal);
        int result = (int) lVal;
        return result;
    }

}