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

//
// RngPack 1.1a by Paul Houle
// http://www.honeylocust.com/RngPack/
//

/**
*
* <TT>RANMAR</TT> is a lagged Fibonacci generator proposed by Marsaglia and
* Zaman and is a good research grade generator.  This version of
* <TT>RANMAR</TT> is based on the paper by James,  which is a good
* reference for the properties of <TT>RANMAR</TT> and several other
* generators.
* 
* <BR>
* <B>REFERENCES:</B>
* <BR>
* F. James, <CITE>Comp. Phys. Comm.</CITE> <STRONG>60</STRONG> (1990) p 329-344
* <BR>
* and was originally described in
* <BR>
* G. Marsaglia, A. Zaman and W.-W Tsang, <CITE>Stat. Prob. Lett</CITE> <STRONG>9</STRONG> (1990) p 35.
* 
* 
* <P>
* <A HREF="/RngPack/src/edu/cornell/lassp/houle/RngPack/Ranmar.java">
* Source code </A> is available. 
*
* @author <A HREF="http://www.honeylocust.com/"> Paul Houle </A> (E-mail: <A HREF="mailto:paul@honeylocust.com">paul@honeylocust.com</A>)
* @version 1.1a
*/


public class Ranmar extends RandomSeedable implements Serializable {

double c,cd,cm,u[],uvec[] ;
int i97,j97 ;

/**
* Default seed.  <CODE>DEFSEED=54217137</CODE>
*/
public static int DEFSEED=54217137;

/**
* The 46,009,220nd prime number,
* he largest prime less than 9*10<SUP>8</SUP>.  Used as a modulus
* because this version of <TT>RANMAR</TT> needs a seed between 0
* and 9*10<SUP>8</SUP> and <CODE>BIG_PRIME</CODE> isn't commensurate
* with any regular period.
* <CODE>BIG_PRIME= 899999963</CODE>
*/
public static int BIG_PRIME=899999963;

/**
*
* Initialize Ranmar with a specified integer seed
*
* @param ijkl seed integer;  <TT>Ranmar(int ijkl)</TT> takes uses
* <TT>ijkl</TT> modulus <TT>BIG_PRIME</TT> as a seed for <TT>RANMAR.</TT>
*
*/

public Ranmar(int ijkl)
{
	ranmarin(Math.abs(ijkl % BIG_PRIME));
};

/**
*
* Initialize Ranmar with a specified long seed
*
* @param ijkl seed long;  <TT>Ranmar(long ijkl)</TT> takes uses
* <TT>ijkl</TT> modulus <TT>BIG_PRIME</TT> as a seed for <TT>RANMAR.</TT>
*
*/

public Ranmar(long ijkl)
{
	ranmarin((int) Math.abs(ijkl % BIG_PRIME));
};



/**
*
* Initialize Ranmar with a default seed taken from Marsaglia and
* Zaman's paper.  Equivalent to <CODE>Ranmar(54217137).</CODE>
*
*/

public Ranmar()
{
	ranmarin(DEFSEED);
};

/**
*
* Seed <TT>RANMAR</TT> from the clock.
*
* <PRE>
* RandomElement e=new Ranmar(new Date());
* </PRE>
*
* @param d a Date object to seed Ranmar with,  typically <CODE>new Date()</CODE>
*
*/

public Ranmar(Date d) {

    ranmarin((int) ClockSeed(d) % BIG_PRIME);
};

/**
*
* Internal methods:  ranmarin is the initialization code for the
* generator.
*
*/

void ranmarin(int ijkl)
{

	int ij,kl;
	int i,ii,j,jj,k,l,m ;
	double s,t ;

	u = new double[97];
        uvec = new double[97];


	ij=ijkl/30082;
	kl=ijkl-30082*ij;

	i = ((ij/177) % 177) + 2 ;
	j = (ij % 177) + 2 ;
	k = ((kl/169) % 178) + 1 ;
	l = kl % 169 ;
	for (ii=0; ii<97; ii++)
		{
	 	s = 0.0 ;
		t = 0.5 ;
		for (jj=0; jj<24; jj++)
			{
			m = (((i*j) % 179) * k) % 179 ;
			i = j ;
			j = k ;
			k = m ;
			l = (53*l + 1) % 169 ;
			if ( ((l*m) % 64) >= 32) s += t ;
			t *= 0.5 ;
		}
		u[ii] = s ;
	}
	c   =  362436.0 / 16777216.0 ;
	cd  = 7654321.0 / 16777216.0 ;
	cm  =16777213.0 / 16777216.0 ;
	i97 = 96 ;
	j97 = 32 ;

};

/**
* The generator
* @return a pseudo random number
*/

final public double raw() {

	double uni;

	uni=u[i97]-u[j97];
	if (uni<0.0) uni+=1.0;
	u[i97]=uni;
	if (--i97<0) i97=96;
	if (--j97<0) j97=96;
	c-=cd;
	if (c<0.0) c+=cm;
	uni-=c;
	if (uni<0.0) uni+=1.0;
	return(uni);
  };	

/**
*
* A version of the generator for filling arrays,  inlined for speed
*
* @param d an array of doubles to be filled
* @param n size of the array
*
*/

final public void raw(double d[],int n) {

	double uni;

	for(int i=0;i<n;i++)
	{
	    uni=u[i97]-u[j97];
	    if (uni<0.0) uni+=1.0;
	    u[i97]=uni;
	    if (--i97<0) i97=96;
	    if (--j97<0) j97=96;
	    c-=cd;
	    if (c<0.0) c+=cm;
	    uni-=c;
	    if (uni<0.0) uni+=1.0;
	    d[i]=uni;
	};
};


};

