/*
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/licenses/publicdomain
 */

import java.util.*;
//import java.util.concurrent.atomic.*;

public class RNGLoops {

    static volatile int total = 0;

    static void x0(Random rng, int iters) {
        long startTime = System.nanoTime();
        int i = iters;
        int sum = 0;
        while (i-- >= 0)
            sum += rng.nextInt();
        total += sum;
        double time = System.nanoTime() - startTime;
        double tpr = time / iters;
        if (iters > 1024 * 1024) {
            System.out.print("0Time : " + tpr);
            System.out.println("\t class: " + rng.getClass());
        }
        
    }

    static void x1(int iters) {
        final Random rng = XorShiftRandomFactory.xorShift1();
        //        final XorShiftRandomFactory.XorShift1 rng = new XorShiftRandomFactory.XorShift1();
        //        final XorShiftRandomFactory.XorShift1 rng = (XorShiftRandomFactory.XorShift1) XorShiftRandomFactory.xorShift1();
        long startTime = System.nanoTime();
        int i = iters;
        int sum = 0;
        while (i-- >= 0)
            sum += rng.nextInt();
        total += sum;
        double time = System.nanoTime() - startTime;
        double tpr = time / iters;
        if (iters > 1024 * 1024)
            System.out.println("1Time : " + tpr);
    }

    static void x4(int iters) {
        final Random rng = XorShiftRandomFactory.xorShift4();
        long startTime = System.nanoTime();
        int i = iters;
        int sum = 0;
        while (i-- >= 0)
            sum += rng.nextInt();
        total += sum;
        double time = System.nanoTime() - startTime;
        double tpr = time / iters;
        if (iters > 1024 * 1024)
            System.out.println("4Time : " + tpr);
    }

    static void x8(int iters) {
        final Random rng = XorShiftRandomFactory.xorShift8();
        long startTime = System.nanoTime();
        int i = iters;
        int sum = 0;
        while (i-- >= 0)
            sum += rng.nextInt();
        total += sum;
        double time = System.nanoTime() - startTime;
        double tpr = time / iters;
        if (iters > 1024 * 1024)
            System.out.println("8Time : " + tpr);
    }

    static void u(int iters) {
        final Random rng = new UnsynchedRandom();
        long startTime = System.nanoTime();
        int i = iters;
        int sum = 0;
        while (i-- >= 0)
            sum += rng.nextInt();
        total += sum;
        double time = System.nanoTime() - startTime;
        double tpr = time / iters;
        if (iters > 1024 * 1024)
            System.out.println("UTime : " + tpr);
    }

    static void r(int iters) {
        java.util.Random rng = new java.util.Random();
        long startTime = System.nanoTime();
        int i = iters;
        int sum = 0;
        while (i-- >= 0)
            sum += rng.nextInt();
        total += sum;
        double time = System.nanoTime() - startTime;
        double tpr = time / iters;
        if (iters > 1024 * 1024)
            System.out.println("RTime : " + tpr);
    }

    public static void main(String[] args) {
        int iters = 1;
        for (int k = 0; k < 4; ++k) {
            System.out.println("Iterations : " + iters);
            for (int i = 0; i < 2; ++i) {
                x0(XorShiftRandomFactory.xorShift1(), iters);
                x0(XorShiftRandomFactory.xorShift4(), iters);
                x0(XorShiftRandomFactory.xorShift8(), iters);
                x0(new UnsynchedRandom(), iters);
                x1(iters);
                x4(iters);
                x8(iters);
                u(iters);
                //                r(iters);
                if (total == 0) System.out.print(" ");
            }
            iters *= 1024;
        }
    }

    public static class UnsynchedRandom extends java.util.Random {
        private final static long multiplier = 0x5DEECE66DL;
        private final static long addend = 0xBL;
        private final static long mask = (1L << 48) - 1;
        private long seed = System.nanoTime();

        UnsynchedRandom() { super(); }
        UnsynchedRandom(long seed) { super(seed); }
        public void setSeed(long seed) {
            super.setSeed(seed);
            this.seed = seed;
        }

        protected final int next(int bits) {  
            long nextseed = (seed * multiplier + addend) & mask;
            seed = nextseed;
            return (int)(nextseed >>> (48 - bits));
        }
    }


}
