//package edu.cornell.lassp.houle.RngPack;
import java.util.*;

//
// RngPack 1.0 by Paul Houle
// http://www.msc.cornell.edu/~houle/rngpack 
//

/**
*
* Ranecu is an advanced multiplicative linear congruential random number
* generator with a period of aproximately 10<SUP>18</SUP>.
* Ranecu is a direct translation from Fortran of the <B>RANECU</B>
* subroutine
* published in the paper
* <BR>
* F. James, <CITE>Comp. Phys. Comm.</CITE> <STRONG>60</STRONG> (1990) p 329-344
* <BR>
* The algorithm was originally described in
* <BR>
* P. L'Ecuyer, <CITE>Commun. ACM.</CITE> <STRONG>1988</STRONG> (1988) p 742
* <BR>
* 
* <P>
* <A HREF="../src/edu/cornell/lassp/houle/RngPack/Ranecu.java" TARGET="edu.cornell.lassp.houle.source">
* Source code </A> is available. 
*
* @author <A HREF="http://www.msc.cornell.edu/~houle"> Paul Houle </A> (E-mail: <A HREF="mailto:houle@msc.cornell.edu">houle@msc.cornell.edu</A>)
* @version 1.0
*/


public class Ranecu extends RandomSeedable {

int iseed1,iseed2;                 

/**
* default iseed1 = 12345
*/
public static int DEFSEED1=12345;

/**
* default iseed2 = 67890
*/

public static int DEFSEED2=67890;

/**
*
* Initialize <BOLD>RANECU</BOLD> with the default seeds from
* James.
*
*/
public Ranecu() {

    iseed1=DEFSEED1;
    iseed2=DEFSEED2;
};

/**
*
* Initialize <BOLD>RANECU</BOLD> with two specified integer seeds.  Use
* this to introduce repeatable seeds.  Equivalent to
*
* <CODE>Ranecu(s1*(long) Integer.MAX_VALUE)+s2)</CODE>
*
* @param s1 seed integer 1 (MSW)
* @param s2 seed integer 2 (LSW)
*
*/

public Ranecu(int s1,int s2){

    iseed1=s1;
    iseed2=s2;
};

/*
*
* Initialize <TT>RANECU</TT> with a long seed.
*
* @param l long integer seed
*/

public Ranecu(long l) {

    iseed1 = (int) l/Integer.MAX_VALUE;
    iseed2 = (int) l%Integer.MAX_VALUE;
};

/*
*
* Initialize <TT>RANECU</TT> from the clock without saving a copy
* of the seed.  Example:
*
* <PRE>
* RandomElement e = new Ranecu(new Date());
* </PRE>
*
* to save the seed for future restarts,  see the <CODE>ClockSeed()</CODE>
* method defined in RandomSeedable.
*
* @param d a date,  typically <CODE>new Date()</CODE>
* @see RandomSeedable#ClockSeed()
*/

public Ranecu(Date d) {
    iseed1 = (int) d.getTime()/Integer.MAX_VALUE;
    iseed2 = (int) d.getTime()%Integer.MAX_VALUE;
};

/**

@see RandomElement#raw
*/

final public double raw() {

    int k,iz;

    k=iseed1/53688;
    iseed1=40014*(iseed1-k*53668)-k*12211;
    if (iseed1<0) iseed1=iseed1+2147483563;

    k=iseed2/52774;
    iseed2=40692*(iseed2-k*52774)-k*3791;
    if (iseed2<0) iseed2=iseed2+2147483399;

    iz=iseed1-iseed2;
    if(iz<1) iz=iz+2147483562;

    return(iz*4.656613e-10);
};

/**
* This is an inline version that returns an array of doubles for speed.
*/


final public void raw(double d[],int n)
{
    int i,k,iz;

    for(i=0;i<n;i++)
    {

        k=iseed1/53688;
        iseed1=40014*(iseed1-k*53668)-k*12211;
        if (iseed1<0) iseed1=iseed1+2147483563;

        k=iseed2/52774;
        iseed2=40692*(iseed2-k*52774)-k*3791;
        if (iseed2<0) iseed2=iseed2+2147483399;

        iz=iseed1-iseed2;
        if(iz<1) iz=iz+2147483562;

        d[i]=iz*4.656613e-10;
    };
};


/**
*
* @return the current generator state as a long.  Can be used to 
* restart the generator where one left off.
*
*/

public long getSeed() { return iseed1*(long) Integer.MAX_VALUE + iseed2; };

};