/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       *
 * http://www.gnu.org/software/gnugo/ for more information.          *
 *                                                                   *
 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,   *
 * 2008, 2009 and 2010 by the Free Software Foundation.              *
 *                                                                   *
 * 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 - version 3 or          *
 * (at your option) any later version.                               *
 *                                                                   *
 * This program is distributed in the hope that it will be useful,   *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *
 * GNU General Public License in file COPYING for more details.      *
 *                                                                   *
 * You should have received a copy of the GNU General Public         *
 * License along with this program; if not, write to the Free        *
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       *
 * Boston, MA 02111, USA.                                            *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <limits.h>
#include <assert.h>

#include "random.h"

/* This is an implementation of the TGFSR (twisted generalized
 * feedback shift register) random number generator TT800, which was
 * published in:
 *
 * Matsumoto, M. and Kurita, Y.: Twisted GFSR generators II.
 * ACM Transactions on Modeling and Computer Simulations,
 * Vol 4, No. 3, July 1994, pp 254--266
 *
 * The generator produces a pseudo-random sequence of 32 bit integers
 * with period 2^800 - 1 and is reported to have excellent
 * equidistribution properties, as well as being fast.
 */


/* Algorithm parameters. */
#define N 25
static const int m = 7;
static const int s = 7;
static const int t = 15;
static const unsigned int a = 0x8ebfd028U;
static const unsigned int b = 0x2b5b2500U;
static const unsigned int c = 0xdb8b0000U;


/* Global state for the random number generator. */
static unsigned int x[N];
static int k;


/* Set when properly seeded. */
static int rand_initialized = 0;

/* We use this to detect whether unsigned ints are bigger than 32
 * bits. If they are we need to clear higher order bits, otherwise we
 * can optimize by not doing the masking.
 */
#define BIG_UINT (UINT_MAX > 0xffffffffU)


/* Iterate the TGFSR once to get a new state which can be used to
 * produce another 25 random numbers.
 */

static void
iterate_tgfsr(void)
{
  int i;
  for (i = 0; i < N - m; i++)
    x[i] = x[i + m]   ^  (x[i] >> 1)  ^  ((x[i] & 1) ? a : 0);
  for (; i < N; i++)
    x[i] = x[i + m - N] ^  (x[i] >> 1)  ^  ((x[i] & 1) ? a : 0);
}


/* Produce a random number from the next word of the internal state.
 */

static unsigned int
next_rand(void)
{
  int y;
  if (!rand_initialized) {
    assert(rand_initialized); /* Abort. */
    gg_srand(1);              /* Initialize silently if assertions disabled. */
  }
  if (++k == N) {
    iterate_tgfsr();
    k = 0;
  }
  y = x[k] ^ ((x[k] << s) & b);
  y ^= ((y << t) & c);
#if BIG_UINT
  y &= 0xffffffffU;
#endif
  return y;
}


/* Seed the random number generator. The first word of the internal
 * state is set by the (lower) 32 bits of seed. The remaining 24 words
 * are generated from the first one by a linear congruential pseudo
 * random generator.
 *
 * FIXME: The constants in this generator has not been checked, but
 * since they only are used to produce a very short sequence, which in
 * turn only is a seed to a stronger generator, it probably doesn't
 * matter much.
 */

void
gg_srand(unsigned int seed)
{
  int i;
  for (i = 0; i < N; i++) {
#if BIG_UINT
    seed &= 0xffffffffU;
#endif
    x[i] = seed;
    seed *= 1313;
    seed += 88897;
  }
  k = N-1; /* Force an immediate iteration of the TGFSR. */
  rand_initialized = 1;
}


/* Obtain one random integer value in the interval [0, 2^31-1].
 */

int
gg_rand(void)
{
  return (int) (next_rand() & 0x7fffffff);
}


/* Obtain one random integer value in the interval [0, 2^32-1].
 */

unsigned int
gg_urand(void)
{
  return next_rand();
}


/* Obtain one random floating point value in the half open interval
 * [0.0, 1.0).
 *
 * If the value is converted to a floating point type with less than
 * 32 bits mantissa (or if the double type should happen to be
 * unusually short), the value 1.0 may be attained.
 */

double
gg_drand(void)
{
  return next_rand() * 2.328306436538696e-10;
}


/* Retrieve the internal state of the random generator.
 */

void
gg_get_rand_state(struct gg_rand_state *state)
{
  int i;
  for (i = 0; i < N; i++)
    state->x[i] = x[i];
  state->k = k;
}


/* Set the internal state of the random number generator.
 */

void
gg_set_rand_state(struct gg_rand_state *state)
{
  int i;
  for (i = 0; i < N; i++)
    x[i] = state->x[i];
  k = state->k;
}


/*
 * Local Variables:
 * tab-width: 8
 * c-basic-offset: 2
 * End:
 */
