/*
Copyright 2002-2008 Greg Kochanski. 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

This program may be downloaded from http://www.sourceforge.org from the "speechresearch" project.
*/
#include <stdio.h>
#include <assert.h>
#include <float.h>
#include <math.h>
#include "gpklib.h"
#include <sys/types.h>
#include <time.h>

typedef unsigned unsigned32;

C static unsigned M1 = 259200;
C static unsigned IA1 = 7141;
C static unsigned IC1 = 54773;
C static double RM1 = ((1.0-DBL_EPSILON)/M1);
C static unsigned M2 = 134456;
C static unsigned IA2 = 8121;
C static unsigned IC2 = 28411;
C static double RM2 = ((1.0-DBL_EPSILON)/M2);
C static unsigned M3 = 243000;
C static unsigned IA3 = 4561;
C static unsigned IC3 = 51349;
C static unsigned M4 = 43237;
C static unsigned IA4 = 4339;
C static unsigned IC4 = 17;
C static double RM4 = ((1.0-DBL_EPSILON)/M4);

#define NR	397

/* Set Idnum to a nonzero number to re-initialize the sequence with the new seed.
	After it uses the seed, ran1() sets the seed to zero.
	Idnum may be a nil pointer.
	Initially, the seed is set from the time, if you haven't explicitly
	initialized it.

	The generator only re-initializes when there is a non-nil pointer to
	a non-zero int.

To use:
	int q = 3334;	# Initialize with a favorite seed.
	while()	{
		x = ran1(&q);
		...
	}


	or


	while()	{
		x = ran1(0);	# Will be initialized by clock on first pass.
		...
	}
	

	It returns a random number between 0 <= x < 1.
	It is built from three of Numerical Recipies "Quick and Dirty"
	random number generators.  Two produce the numbers, and one
	is used to shuffle the results.
	*/
double ran1(int *idum)
{
	static unsigned32 ix1, ix2, ix3, ix4;
	static double r[NR];
	double temp;
	static int iff=0;
	int jtmp;

	if ((idum && *idum!=0) || iff==0) {
		unsigned tmp = (idum&&*idum) ? *idum : time(0);
		int j;
		iff = 1;
		ix1 = (IC1+tmp) % M1;
		ix1 = (IA1*ix1+IC1) % M1;
		ix2 = ix1 % M2;
		ix1 = (IA1*ix1+IC1) % M1;
		ix3 = (ix1*3+5) % M3;
		ix4 = (ix1*7+11) % M4;
		for(j=0; j<NR; j++) {
			ix1 = (IA1*ix1+IC1) % M1;
			ix2 = (IA2*ix2+IC2) % M2;
			r[j] = (ix1+ix2*RM2)*RM1;
		    assert(r[j]>=0.0 && r[j]<1.0);
		}
		if(idum)
			*idum = 0;
	}
	ix1 = (IA1*ix1+IC1) % M1;
	ix2 = (IA2*ix2+IC2) % M2;
	ix3 = (IA3*ix3+IC3) % M3;
	ix4 = (IA4*ix4+IC4) % M4;
	jtmp = (int)((NR*ix3)/M3);
	assert(jtmp>=0 && jtmp<NR);
	temp = r[jtmp];
	assert(temp>=0.0 && temp<2.0);
	r[jtmp] = (ix1+ix2*RM2)*RM1 + ix4*RM4;
	return temp>=1.0 ? temp-1.0 : temp;
}

#undef M1
#undef IA1
#undef IC1
#undef RM1
#undef M2
#undef IA2
#undef IC2
#undef RM2
#undef M3
#undef IA3
#undef IC3

double ran1a(int *idnum)
{
 return ran1(idnum);
}


double Nnoise(int *idum)
{
 static int extra = 0;
 static double store = 0.0;

 if(idum && *idum!=0)
	extra = 0;
 else if(extra)	{extra = 0; return store;}

 extra = 1;
 const double x1  = ran1(idum);
 const double x2 = ran1(idum);
 store = sqrt(-2.0*log(x1)) * cos(2*M_PI*x2);
 return sqrt(-2.0*log(x2)) * cos(2*M_PI*x1);
}
