/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include <stdlib.h>

/****************************************************************************/
/*					Local definitions										*/
/****************************************************************************/

/*
*	The random number generator state
*/

typedef struct {

	unsigned char	n;				// Length of the array
	unsigned char	i;				// Index of the oldest element
	unsigned char	j;				// Index of the tap element
	unsigned char	u;				// An unused alignment byte
	unsigned int	d[];			// The actual array

} RSTAT;

/****************************************************************************/
/*					Public API functions									*/
/****************************************************************************/

/** @addtogroup stdlib */
/**	@{ */

/**
*	Initialises the random number generator.
*
*	This function takes a 32-bit seed, and array of integers and the
*	size of that array. It then initialises the array so that it can
*	be used as the state for a pseudo-random generator.
*
*	The integer array should be 2, 8, 16, 32 or 64 ints long. Sizes other
*	than the above will be rejected. The goodness and the period of the
*	generator increases as you increase the size. Larger sizes mean longer
*	execution time for <i>this</i> function, but the time consumption of
*	the random_r() function remains the same.
*
*	@param	seed	The seed of the generator. It should not be 0 and should
*					not be negative, if it is, then it is taken as 1.
*
*	@param	state	An array of 2, 8, 16, 32 or 64 integers, this will be
*					the random number generator's state. This array must
*					not be modified after the call except by the random_r()
*					routine itself.
*
*	@param	size	The size of the array, as returned by the <tt>sizeof()</tt>
*					operator (i.e. size in bytes, not in words!)
*
*	@return			The state pointer, if it succeeded or NULL, if the
*					size argument wasn't one of the allowed values.
*/

int		*srandom_r( int seed, int *state, size_t size )
{
RSTAT	*stat = (RSTAT *) state;
int		x, i;
div_t	qr;

	// We support queue sizes of 1, 7, 15, 31 and 63 words.
	// That corresponds to 8, 32, 64, 128 and 256 bytes of state size.

	if ( ! ( seed &= 0x7fffffff ) ) seed = 1;

	switch ( size ) {

		case 8:

			stat->n = 1;
			stat->i = 0;
			stat->j = 0;
			break;

		case 32:

			stat->n = 7;
			stat->i = 7;
			stat->j = 3;
			break;

		case 64:

			stat->n = 15;
			stat->i = 15;
			stat->j = 14;
			break;

		case 128:

			stat->n = 31;
			stat->i = 31;
			stat->j = 28;
			break;

		case 256:

			stat->n = 63;
			stat->i = 63;
			stat->j = 62;
			break;

		default:
			return( NULL );
	}

	// Fill the state buffer.
	//	S[0] = seed
	//	S[n+1] = ( S[n]*16807 ) % ( 2^31 - 1 )
	// Note that we store the array the other way around.

	stat->d[ stat->n - 1 ] = seed;

	for ( x = seed, i = stat->n - 2 ; i >= 0 ; i-- ) {

		// This step calculates x' = ( x * 16807 ) % ( 2^31 - 1 );
		// The magic numbers below:
		// -	2147483647	is 2^31-1
		// - 	127773 		is (2^31-1) / 16807
		// -	2836		is (2^31-1) % 127773.

		qr = div( x, 127773 );
		x  = 16807 * qr.rem - 2836 * qr.quot;
		if ( x < 0 ) x += 2147483647;

		stat->d[ i ] = x;
	}

	// Now we have to throw away the first 10 full cycles

	for ( i = stat->n * 10 ; i-- ; ) random_r( state );

	// Done.

	return( state );
}

/**
*	Random number generator.
*
*	The function receives a state, which must have been prepared by the
*	srandom_r() function, and returns a pseudorandom number and updates
*	the state. The state must not be modified between calls and if it
*	is shared between execution contexts, then mutual exclusivity must
*	be ascertained.
*
*	If the size of the state is 2 words (see the srandom_r() function),
*	then the classical rand() algorithm is used, which is a linear
*	congruential generator. If the size is 8, 16, 32 or 64 words, then
*	an additive lagged Fibonacci generator is used. The runtime of the
*	latter generator is independent of the state size and it is very fast.
*
*	Note that although the generated numbers are high quality in terms
*	of randomness (they have good statistical properties), they are
*	<b>not</b> cryptographically safe. If you want to use this generator
*	for cryptography, you should feed its output to a hash or cipher
*	function and use the result of that as your random sequence. In
*	addition, for cryptographic purposes you must assure that your seed
*	is indeed random, preferably generated by some truly random process.
*
*	@param	state	The state array which must have been initialised by
*					the srandom_r() function.
*
*	@return			A random number between 0 and RAND_MAX, which is
*					actually defined as 2<sup>31</sup>-1 (i.e. the largest
*					32-bit signed positive integer).
*/

int		random_r( int *state )
{
RSTAT		*stat = (RSTAT *) state;
unsigned	x;
int			i, j, n;

	if ( stat->n == 1 ) {

		// We fall back to the standard 'rand()' algorithm

		x  = stat->d[ 0 ];
		x *= 1103515245;
		x += 12345;
		stat->d[ 0 ] = x;
	}
	else {

		i = stat->i;
		j = stat->j;
		n = stat->n;

		x = stat->d[ i ] + stat->d[ j ];
		stat->d[ i ] = x;

		if ( --i < 0 ) i = n;
		if ( --j < 0 ) j = n;

		stat->i = i;
		stat->j = j;
	}

	return( x >> 1 );
}

/** @} */

