package com.thealgorithms.others;

/**
 * *
 * A pseudorandom number generator.
 *
 * @author Tobias Carryer
 * @date October 10, 2017
 */
public class LinearCongruentialGenerator {

    private final double a;
    private final double c;
    private final double m;
    private double previousValue;

    /**
     * *
     * These parameters are saved and used when nextNumber() is called. The
     * current timestamp in milliseconds is used as the seed.
     *
     * @param multiplier
     * @param increment
     * @param modulo The maximum number that can be generated (exclusive). A
     * common value is 2^32.
     */
    public LinearCongruentialGenerator(double multiplier, double increment, double modulo) {
        this(System.currentTimeMillis(), multiplier, increment, modulo);
    }

    /**
     * *
     * These parameters are saved and used when nextNumber() is called.
     *
     * @param seed
     * @param multiplier
     * @param increment
     * @param modulo The maximum number that can be generated (exclusive). A
     * common value is 2^32.
     */
    public LinearCongruentialGenerator(double seed, double multiplier, double increment, double modulo) {
        this.previousValue = seed;
        this.a = multiplier;
        this.c = increment;
        this.m = modulo;
    }

    /**
     * The smallest number that can be generated is zero. The largest number
     * that can be generated is modulo-1. modulo is set in the constructor.
     *
     * @return a pseudorandom number.
     */
    public double nextNumber() {
        previousValue = (a * previousValue + c) % m;
        return previousValue;
    }

    public static void main(String[] args) {
        // Show the LCG in action.
        // Decisive proof that the LCG works could be made by adding each number
        // generated to a Set while checking for duplicates.
        LinearCongruentialGenerator lcg = new LinearCongruentialGenerator(1664525, 1013904223, Math.pow(2.0, 32.0));
        for (int i = 0; i < 512; i++) {
            System.out.println(lcg.nextNumber());
        }
    }
}
