// RAN2.C
// This contains a slightly modified version of
// the ran2() function given in Numerical Recipes, p.282.
// © 2021 Peter J. Meyer
// ran2() has a period of > 2 x 10^18 whereas
// ran1() has a period only of c. 2 x 10^9.
#define true 1
#define false 0
#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 EPS (1e-16) // Changed from 1.2e-7
#define RNMX (1.0-EPS)
static double num_calls = 0.0;
static double period_length = 2e18;
static int period_length_exceeded = false;
static long xn32 = -1;
long iy=0;
void reset_num_ran2_calls(void);
// Returns a "uniform random deviate" between 0.0 and 1.0 (exclusive).
/*-------------*/
double ran2(void)
{
long j, k;
static long ix=123456789;
// static long iy=0;
static long iv[NTAB];
double result;
num_calls += 1.0;
if ( num_calls > period_length )
period_length_exceeded = true;
if ( xn32 <= 0 )
{
// Initialize
if ( xn32 == 0 )
xn32 = 1;
else // xn32 < 0
xn32 = -xn32;
ix = xn32;
// Load the shuffle table (after 8 warm-ups).
for ( j=NTAB+7; j>=0; j-- )
{
k = xn32/IQ1;
xn32 = IA1*(xn32-k*IQ1) - IR1*k;
if ( xn32 < 0 )
xn32 += IM1;
if ( j < NTAB )
iv[j] = xn32;
}
iy = iv[0];
}
k = xn32/IQ1; // Start here when not initializing.
xn32 = IA1*(xn32 - k*IQ1) - IR1*k; // Compute xn32 = (IA1*xn32)%IM1 without overflow.
if ( xn32 < 0 )
xn32 += IM1;
k = ix/IQ2; // Compute ix%IM2 likewise.
ix = IA2*(ix - k*IQ2) - IR2*k;
if ( ix < 0 )
ix += IM2;
j = iy/NDIV; // Will be in the range 0 through NTAB-1.
iy = iv[j] - ix; // Here xn32 is shuffled and xn32
// and ix are combined to generate output.
iv[j] = xn32; // and refill the shuffle table.
if ( iy < 1 )
iy += IMM1;
result = AM*iy;
return ( result > RNMX ? RNMX : result ); // So as not to return 1.0.
}
/*-----------------------------*/
void init_ran2(unsigned int seed)
{
int i;
xn32 = seed;
xn32 = xn32*(xn32+1) + 7; // Make sure xn32 is odd.
if ( xn32 > 0 ) // Make sure xn32 is negative
xn32 = -xn32;
ran2(); // Initialise
for ( i=0; i<64; i++ ) // Run ran2() a bit.
ran2();
reset_num_ran2_calls(); // Reset to 0.
}
/*---------------------------*/
void reset_num_ran2_calls(void)
{
num_calls = 0.0;
}
/*-----------------------*/
double num_ran2_calls(void)
{
return ( num_calls );
}
/*--------------------------*/
int ran2_period_exceeded(void)
{
return ( period_length_exceeded );
}