//=========================================================================
//      Random number generator (Algorithm by R. M. Ziff)
//=========================================================================

#ifndef RND_ZIFF_H
#define RND_ZIFF_H

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
void InitRandom (int randomize=11);                    // Initialization
double rnd              (void);                          // 0...1
double rnd              (double max);                    // 0...max
double rnd              (double min, double max);        // min...max
int rndint              (int num=2);                     // 0,1,...num-1
int rndint              (int min, int max);              // min,min+1,...,max-1
*/

//-----------------------------------------------------------------------------

const int Random_A = 471;
const int Random_B = 1586;
const int Random_C = 6988;
const int Random_D = 9689;
const int Random_M = 16383;
const unsigned int Random_Max = 2147483648U;
int Random_nd;
int Random_ra[16384];

void InitRandom (size_t randomize) {
    srandom(randomize);
    Random_nd = random();
    for (int i=0; i<=Random_M; ++i)
        Random_ra[i] = random();
}

#define RandomInteger (++Random_nd, Random_ra[Random_nd & Random_M] = \
                Random_ra[(Random_nd-Random_A) & Random_M] ^ \
                Random_ra[(Random_nd-Random_B) & Random_M] ^ \
                Random_ra[(Random_nd-Random_C) & Random_M] ^ \
                Random_ra[(Random_nd-Random_D) & Random_M])

inline double rnd(void) { return (double)RandomInteger/Random_Max; } 


//-------------------Auxiliary random number routines---------------------

inline double rnd_dbl (double max)                  {return max*rnd();}
inline double rnd_dbl2 (double min, double max)      {return min+(max-min)*rnd();}
inline int rnd_int (int num)                   {return (int)(num*rnd()); }
inline int rnd_int2 (int min, int max)            {return min+rndint(max-min+1); }

double rndgaussian() {
    double x1, x2, w;

    do {
        x1 = 2.0 * rnd() - 1.0;
        x2 = 2.0 * rnd() - 1.0;
        w = x1 * x1 + x2 * x2;
    } while ( w >= 1.0 );
                    
    //      w = sqrt( (-2.0 * log( w ) ) / w );
    //      double y1, y2;
    //      y1 = x1 * w;
    //      y2 = x2 * w;

    return x1 * sqrt( (-2.0 * log( w ) ) / w );
}

#endif // RND_ZIFF_H
