/*
 * random.c
 *
 * Copyright (C) Klaus Kudielka
 *
 * Various random number generators picked from the Numerical Recipes
 * book
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <math.h>
#include "random.h"



/* Pseudorandom bit sequence (from "Numerical recipes") */

static int iseed;

int discrete(void)
{
  if (iseed & 0x00020000) {
    iseed=((iseed ^ 0x00020013) << 1) | 1;
    return 1;
  } else {
    iseed <<= 1;
    return -1;
  }
}

int seedDiscrete(int seed) {
  iseed = seed;
  return seed;
}



/* Uniform random variable generator (from "Numerical recipes")*/

#define IM1 2147483563
#define IM2 2147483399
#define AM (1.0/IM1)
#define IMM1 (IM1-1)
#define IA1 40014
#define IA2 40692
#define IQ1 53668
#define IQ2 52774
#define IR1 12211
#define IR2 3791
#define NTAB 32
#define NDIV (1+IMM1/NTAB)
#define RNMX (1.0-DBL_EPSILON)

static int idum;
static int idum2;
static int iy;
static int iv[NTAB];

double randomUniform(void)
{
  int j;
  double temp;

  j=idum/IQ1;
  idum=IA1*(idum-j*IQ1)-j*IR1;
  if (idum < 0) idum += IM1;
  j=idum2/IQ2;
  idum2=IA2*(idum2-j*IQ2)-j*IR2;
  if (idum2 < 0) idum2 += IM2;
  j=iy/NDIV;
  iy=iv[j]-idum2;
  iv[j] = idum;
  if (iy < 1) iy += IMM1;
  if ((temp=AM*iy) > RNMX) return RNMX;
  else return temp;
}



/* Initialize uniform random number generator */

void seedRandom(int seed) {
  int j, k;

  if (seed < 1) idum = 1;
  else idum = seed;
  idum2=idum;
  for (j=NTAB+7;j>=0;j--) {
    k=idum/IQ1;
    idum=IA1*(idum-k*IQ1)-k*IR1;
    if (idum < 0) idum += IM1;
    if (j < NTAB) iv[j] = idum;
  }
  iy=iv[0];
  return;
}



/* Gaussian random variable generator (from "Numerical Recipes") */

void randomGaussian(double *r1, double *r2)
{
  double fac,rsq,v1,v2;

  do {
    v1=2.0*randomUniform()-1.0;
    v2=2.0*randomUniform()-1.0;
    rsq=v1*v1+v2*v2;
  } while (rsq >= 1.0 || rsq == 0.0);
  fac=sqrt(-2.0*log(rsq)/rsq);
  *r1=v1*fac;
  *r2=v2*fac;
}


