/***************************************************************************
* Rand.h  (Random Number Generators)                                       *
*                                                                          *
* Header file for Rand.C, pseudo-random number utilities.  Rand is the     *
* base class for several different algorithms for generating pseudo-random *
* numbers.  Any method can generate individual samples or arrays of        *
* samples using "Eval".  The random seed can be reset at any time by       *
* calling "Seed" with any integer.  Random permutations of the integers    *
* 0,1,...(n-1) are generated by "Perm(n,P)".                               *
*                                                                          *
*   HISTORY                                                                *
*      Name    Date        Description                                     *
*                                                                          *
*      arvo    08/04/97    Changed to virtual functions.                   *
*      arvo    06/06/93    Optimization, especially for array evaluators.  *
*      arvo    10/06/91    Converted to C++                                *
*      arvo    11/20/89    Added "gen_seed" function to handle.            *
*      arvo    10/30/89    "state" allocation now done in rand_alloc.      *
*      arvo    07/08/89    Initial coding.                                 *
*                                                                          *
*--------------------------------------------------------------------------*
* Copyright (C) 1989, James Arvo                                           *
*                                                                          *
* 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.  See http://www.fsf.org/copyleft/gpl.html      *
*                                                                          *
* This program is distributed in the hope that it will be useful, but      *
* WITHOUT EXPRESS OR IMPLIED WARRANTY of merchantability or fitness for    *
* any particular purpose.  See the GNU General Public License for more     *
* details.                                                                 *
*                                                                          *
***************************************************************************/
#ifndef __RAND_INCLUDED__
#define __RAND_INCLUDED__

namespace ArvoMath {

	// Base class for random number generators.  This class contains
	// several pure virtual functions, so it cannot be instanced directly.

	class RandGen {
	public:
		RandGen() {}
		virtual float Eval(                  ) = 0;
		virtual void  Eval( int n, float x[] ) = 0;
		virtual void  Seed( long seed        ) = 0;
	public:
		void  Perm( int n, int P[] );
		float Interval( float a, float b );
		void  Eval( float &x ) { x = Eval(); }
	};


	// Method 1: From "Numerical Recipes," by William H. Press, Brian P. 
	// Flannery, Saul A. Teukolsky, and William T. Vetterling, p. 197.

	class RandGen_1 : public RandGen {
	public:
		RandGen_1(           ) { Seed( 1    ); }
		RandGen_1( long seed ) { Seed( seed ); }
		virtual float Eval(                  );
		virtual void  Eval( int n, float x[] );
		virtual void  Seed( long seed        );
	private: 
		long index; 
		long seed;
		long shuffle[ 98 ];
	};


	// Method 2: From "The Multiple Prime Random Number Generator," by 
	// Alexander Haas, ACM Transactions on Mathematical Software, 
	// Vol. 13, No. 4, December 1987, pp. 368-381.                                                      *

	class RandGen_2 : public RandGen {
	public:
		RandGen_2(           ) { Seed( 1    ); }
		RandGen_2( long seed ) { Seed( seed ); }
		virtual float Eval(                  );
		virtual void  Eval( int n, float x[] );
		virtual void  Seed( long seed        );
	private: 
		long r;  
		long m;
		long i;
		long j;
	};


	// Method 3: From "A More Portable Fortran Random Number Generator," 
	// by Linus Schrage, ACM Transactions on Mathematical Software, 
	// Vol. 5, No, 2, June 1979, pp. 132-138.                                                 *

	class RandGen_3 : public RandGen {
	public:
		RandGen_3(           ) { Seed( 1    ); }
		RandGen_3( long seed ) { Seed( seed ); }
		virtual float Eval(                  );
		virtual void  Eval( int n, float x[] );
		virtual void  Seed( long seed        );
	private:
		long ix;
	};


	inline float RandGen::Interval( float a, float b )
	{
		return ( a < b ) ?
			a + Eval() * ( b - a ) :
		b + Eval() * ( a - b ) ;
	}
};
#endif
