// Copyright 1999
// College of Computer Science
// Northeastern University Boston MA 02115

// This software may be used for educational purposes as long as this copyright
// notice is retained at the top of all files

// Should this software be modified, the words "Modified from Original" must be
// included as a comment below this notice

// All publication rights are retained.  This software or its documentation may
// not be published in any media either in whole or in part.

///////////////////////////////////////////////////////////////////////////////

// Random.cpp

///////////////////////////////////////////////////////////////////////////////

#include "CoreTools.h"				// needed for core tools compile in Win32

#include "Random.h"


long TheRandomSeed = 1;				// seed


// constants needed in NextRandom

const long m = 16807;				// seed multiplier
const long q = maximum_long / m;	// quotient:  2147483647 / 16807 = 127773
const long r = maximum_long % m;	// remainder: 2147483647 % 16807 =   2836


// constant needed in NextDouble

const double ML = double(maximum_long);


void SetRandomSeed(long seed) {
	if (MinRandom <= seed && seed <= MaxRandom)
		TheRandomSeed = seed;
	else {
		unsigned long when = clock();	// get clock time
		
		if (when == 0) when = 1;		// fix error
		
		while (when > MaxRandom)		// force in range
			when -= MaxRandom;
			
		TheRandomSeed = when;			// choose as seed
	}
}


long NextRandom() {
	long hi	= TheRandomSeed / q;
	long lo = TheRandomSeed % q;
	long test = m * lo - r * hi;
	
	if (test > 0)
		TheRandomSeed = test;
	else
		TheRandomSeed = test + maximum_long;
	
	return TheRandomSeed;
}


double RandomDouble(double a, double b) {
	long	n = NextRandom();		// n is the next random long
	double	p = double(n) / ML;		// ratio p satisfies 0 < p < 1
	
	return	(a + (b - a) * p);		// linear interpolation from a to b
}


long RandomLong(long a, long b) {
	long	n = NextRandom();		// n is the next random long
	
	if (a > b) {					// force a <= b
		long c = a;
		a = b;
		b = c;
	}
	
	if (a <= 0) {					// force b-a <= MaxRandom
		long c = a + MaxRandom;
		if (b > c)
			b = c;
	}
	
	long	d = b - a + 1;			// d = number of values from a to b
	
	return	a + n % d;				// note: a <= a + n % d <= b
}



void RandomNumber::SetRandomSeed(long seed) {
	if (MinRandom <= seed && seed <= MaxRandom)
		TheRandomSeed = seed;
	else {
		unsigned long when = clock();	// get clock time
		
		if (when == 0) when = 1;		// fix error
		
		while (when > MaxRandom)		// force in range
			when -= MaxRandom;
			
		TheRandomSeed = when;			// choose as seed
	}
}


long RandomNumber::NextRandom() {
	long hi	= TheRandomSeed / q;
	long lo = TheRandomSeed % q;
	long test = m * lo - r * hi;
	
	if (test > 0)
		TheRandomSeed = test;
	else
		TheRandomSeed = test + maximum_long;
	
	return TheRandomSeed;
}


double RandomNumber::RandomDouble(double a, double b) {
	long	n = NextRandom();		// n is the next random long
	double	p = double(n) / ML;		// ratio p satisfies 0 < p < 1
	
	return	(a + (b - a) * p);		// linear interpolation from a to b
}


long RandomNumber::RandomLong(long a, long b) {
	long	n = NextRandom();		// n is the next random long
	
	if (a > b) {					// force a <= b
		long c = a;
		a = b;
		b = c;
	}
	
	if (a <= 0) {					// force b-a <= MaxRandom
		long c = a + MaxRandom;
		if (b > c)
			b = c;
	}
	
	long	d = b - a + 1;			// d = number of values from a to b
	
	return	a + n % d;				// note: a <= a + n % d <= b
}

