Blame rng/ranmar.c

Packit 67cb25
/* rng/ranmar.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <stdlib.h>
Packit 67cb25
#include <gsl/gsl_rng.h>
Packit 67cb25
Packit 67cb25
/* This is the RANMAR lagged fibonacci generator of Marsaglia, Zaman
Packit 67cb25
   and Tsang.  The sequence is a series of 24-bit integers, x_n,
Packit 67cb25
Packit 67cb25
   x_n = (y_n - c_n + 2^24) mod 2^24
Packit 67cb25
Packit 67cb25
   where,
Packit 67cb25
Packit 67cb25
   y_n = (y_{n-97) - y_{n-33} + 2^24) mod 2^24
Packit 67cb25
   c_n = (c_{n-1} - 7654321 + 2^24 - 3) mod (2^24 - 3)
Packit 67cb25
Packit 67cb25
   The period of this generator is 2^144.
Packit 67cb25
Packit 67cb25
   The generator provides about 900 million different subsequences
Packit 67cb25
   each of length O(10^30). Thus each seed up to 900,000,000 gives an
Packit 67cb25
   independent sequence.
Packit 67cb25
Packit 67cb25
   Although it was good in its day this generator now has known
Packit 67cb25
   statistical defects and has been superseded by RANLUX.
Packit 67cb25
Packit 67cb25
   From: F. James, "A Review of Pseudorandom number generators",
Packit 67cb25
   Computer Physics Communications 60, 329 (1990).
Packit 67cb25
Packit 67cb25
   G. Marsaglia, A. Zaman and W.W. Tsang, Stat. Prob. Lett. 9, 35 (1990)  */
Packit 67cb25
Packit 67cb25
static inline unsigned long int ranmar_get (void *vstate);
Packit 67cb25
static double ranmar_get_double (void *vstate);
Packit 67cb25
static void ranmar_set (void *state, unsigned long int s);
Packit 67cb25
Packit 67cb25
static const unsigned long int two24 = 16777216;        /* 2^24 */
Packit 67cb25
Packit 67cb25
typedef struct
Packit 67cb25
  {
Packit 67cb25
    unsigned int i;
Packit 67cb25
    unsigned int j;
Packit 67cb25
    long int carry;
Packit 67cb25
    unsigned long int u[97];
Packit 67cb25
  }
Packit 67cb25
ranmar_state_t;
Packit 67cb25
Packit 67cb25
static inline unsigned long int
Packit 67cb25
ranmar_get (void *vstate)
Packit 67cb25
{
Packit 67cb25
  ranmar_state_t *state = (ranmar_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  unsigned int i = state->i;
Packit 67cb25
  unsigned int j = state->j;
Packit 67cb25
  long int carry = state->carry;
Packit 67cb25
Packit 67cb25
  long int delta = state->u[i] - state->u[j];
Packit 67cb25
Packit 67cb25
  if (delta < 0)
Packit 67cb25
    delta += two24 ;
Packit 67cb25
  
Packit 67cb25
  state->u[i] = delta;
Packit 67cb25
Packit 67cb25
  if (i == 0)
Packit 67cb25
    {
Packit 67cb25
      i = 96;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      i--;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->i = i;
Packit 67cb25
Packit 67cb25
  if (j == 0)
Packit 67cb25
    {
Packit 67cb25
      j = 96;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      j--;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->j = j;
Packit 67cb25
Packit 67cb25
  carry += - 7654321 ;
Packit 67cb25
  
Packit 67cb25
  if (carry < 0)
Packit 67cb25
    carry += two24 - 3;
Packit 67cb25
  
Packit 67cb25
  state->carry = carry ;
Packit 67cb25
Packit 67cb25
  delta += - carry ;
Packit 67cb25
  
Packit 67cb25
  if (delta < 0)
Packit 67cb25
    delta += two24 ;
Packit 67cb25
Packit 67cb25
  return delta;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static double
Packit 67cb25
ranmar_get_double (void *vstate)
Packit 67cb25
{
Packit 67cb25
  return ranmar_get (vstate) / 16777216.0 ;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
ranmar_set (void *vstate, unsigned long int s)
Packit 67cb25
{
Packit 67cb25
  ranmar_state_t *state = (ranmar_state_t *) vstate;
Packit 67cb25
  
Packit 67cb25
  unsigned long int ij = s / 30082 ;
Packit 67cb25
  unsigned long int kl = s % 30082 ;
Packit 67cb25
  
Packit 67cb25
  int i = (ij / 177) % 177 + 2 ;
Packit 67cb25
  int j = (ij % 177) + 2 ;
Packit 67cb25
  int k = (kl / 169) % 178 + 1 ;
Packit 67cb25
  int l = (kl % 169) ;
Packit 67cb25
Packit 67cb25
  int a, b;
Packit 67cb25
  
Packit 67cb25
  for (a = 0; a < 97; a++)
Packit 67cb25
    {
Packit 67cb25
      unsigned long int sum = 0 ;
Packit 67cb25
      unsigned long int t = two24 ;
Packit 67cb25
Packit 67cb25
      for (b = 0; b < 24; b++)
Packit 67cb25
        {
Packit 67cb25
          unsigned long int m = (((i * j) % 179) * k) % 179 ;
Packit 67cb25
          i = j ;
Packit 67cb25
          j = k ;
Packit 67cb25
          k = m ;
Packit 67cb25
          l = (53 * l + 1) % 169 ;
Packit 67cb25
          t >>= 1 ;
Packit 67cb25
          
Packit 67cb25
          if ((l * m) % 64 >= 32)
Packit 67cb25
            sum += t ;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      state->u[a] = sum ;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  state->i = 96;
Packit 67cb25
  state->j = 32;
Packit 67cb25
  state->carry = 362436 ;
Packit 67cb25
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static const gsl_rng_type ranmar_type =
Packit 67cb25
{"ranmar",                      /* name */
Packit 67cb25
 0x00ffffffUL,                  /* RAND_MAX */
Packit 67cb25
 0,                             /* RAND_MIN */
Packit 67cb25
 sizeof (ranmar_state_t),
Packit 67cb25
 &ranmar_set,
Packit 67cb25
 &ranmar_get,
Packit 67cb25
 &ranmar_get_double};
Packit 67cb25
Packit 67cb25
const gsl_rng_type *gsl_rng_ranmar = &ranmar_type;