Blame rng/uni32.c

Packit 67cb25
/* rng/uni32.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
/**
Packit 67cb25
  This is a lagged Fibonacci generator which supposedly excellent
Packit 67cb25
  statistical properties (I do not concur)
Packit 67cb25
Packit 67cb25
  I got it from the net and translated into C.
Packit 67cb25
Packit 67cb25
* ======================================================================
Packit 67cb25
* NIST Guide to Available Math Software.
Packit 67cb25
* Fullsource for module UNI from package CMLIB.
Packit 67cb25
* Retrieved from CAMSUN on Tue Oct  8 14:04:10 1996.
Packit 67cb25
* ======================================================================
Packit 67cb25
Packit 67cb25
C***BEGIN PROLOGUE  UNI
Packit 67cb25
C***DATE WRITTEN   810915
Packit 67cb25
C***REVISION DATE  830805
Packit 67cb25
C***CATEGORY NO.  L6A21
Packit 67cb25
C***KEYWORDS  RANDOM NUMBERS, UNIFORM RANDOM NUMBERS
Packit 67cb25
C***AUTHOR    BLUE, JAMES, SCIENTIFIC COMPUTING DIVISION, NBS
Packit 67cb25
C             KAHANER, DAVID, SCIENTIFIC COMPUTING DIVISION, NBS
Packit 67cb25
C             MARSAGLIA, GEORGE, COMPUTER SCIENCE DEPT., WASH STATE UNIV
Packit 67cb25
C
Packit 67cb25
C***PURPOSE  THIS ROUTINE GENERATES QUASI UNIFORM RANDOM NUMBERS ON [0,1
Packit 67cb25
C             AND CAN BE USED ON ANY COMPUTER WITH WHICH ALLOWS INTEGERS
Packit 67cb25
C             AT LEAST AS LARGE AS 32767.
Packit 67cb25
C***DESCRIPTION
Packit 67cb25
C
Packit 67cb25
C       THIS ROUTINE GENERATES QUASI UNIFORM RANDOM NUMBERS ON THE INTER
Packit 67cb25
C       [0,1).  IT CAN BE USED WITH ANY COMPUTER WHICH ALLOWS
Packit 67cb25
C       INTEGERS AT LEAST AS LARGE AS 32767.
Packit 67cb25
C
Packit 67cb25
C
Packit 67cb25
C   USE
Packit 67cb25
C       FIRST TIME....
Packit 67cb25
C                   Z = UNI(JD)
Packit 67cb25
C                     HERE JD IS ANY  N O N - Z E R O  INTEGER.
Packit 67cb25
C                     THIS CAUSES INITIALIZATION OF THE PROGRAM
Packit 67cb25
C                     AND THE FIRST RANDOM NUMBER TO BE RETURNED AS Z.
Packit 67cb25
C       SUBSEQUENT TIMES...
Packit 67cb25
C                   Z = UNI(0)
Packit 67cb25
C                     CAUSES THE NEXT RANDOM NUMBER TO BE RETURNED AS Z.
Packit 67cb25
C
Packit 67cb25
C
Packit 67cb25
C..................................................................
Packit 67cb25
C   NOTE: USERS WHO WISH TO TRANSPORT THIS PROGRAM FROM ONE COMPUTER
Packit 67cb25
C         TO ANOTHER SHOULD READ THE FOLLOWING INFORMATION.....
Packit 67cb25
C
Packit 67cb25
C   MACHINE DEPENDENCIES...
Packit 67cb25
C      MDIG = A LOWER BOUND ON THE NUMBER OF BINARY DIGITS AVAILABLE
Packit 67cb25
C              FOR REPRESENTING INTEGERS, INCLUDING THE SIGN BIT.
Packit 67cb25
C              THIS VALUE MUST BE AT LEAST 16, BUT MAY BE INCREASED
Packit 67cb25
C              IN LINE WITH REMARK A BELOW.
Packit 67cb25
C
Packit 67cb25
C   REMARKS...
Packit 67cb25
C     A. THIS PROGRAM CAN BE USED IN TWO WAYS:
Packit 67cb25
C        (1) TO OBTAIN REPEATABLE RESULTS ON DIFFERENT COMPUTERS,
Packit 67cb25
C            SET 'MDIG' TO THE SMALLEST OF ITS VALUES ON EACH, OR,
Packit 67cb25
C        (2) TO ALLOW THE LONGEST SEQUENCE OF RANDOM NUMBERS TO BE
Packit 67cb25
C            GENERATED WITHOUT CYCLING (REPEATING) SET 'MDIG' TO THE
Packit 67cb25
C            LARGEST POSSIBLE VALUE.
Packit 67cb25
C     B. THE SEQUENCE OF NUMBERS GENERATED DEPENDS ON THE INITIAL
Packit 67cb25
C          INPUT 'JD' AS WELL AS THE VALUE OF 'MDIG'.
Packit 67cb25
C          IF MDIG=16 ONE SHOULD FIND THAT
Packit 67cb25
   Editors Note: set the seed using 152 in order to get uni(305)
Packit 67cb25
   -jt
Packit 67cb25
C            THE FIRST EVALUATION
Packit 67cb25
C              Z=UNI(305) GIVES Z=.027832881...
Packit 67cb25
C            THE SECOND EVALUATION
Packit 67cb25
C              Z=UNI(0) GIVES   Z=.56102176...
Packit 67cb25
C            THE THIRD EVALUATION
Packit 67cb25
C              Z=UNI(0) GIVES   Z=.41456343...
Packit 67cb25
C            THE THOUSANDTH EVALUATION
Packit 67cb25
C              Z=UNI(0) GIVES   Z=.19797357...
Packit 67cb25
C
Packit 67cb25
C***REFERENCES  MARSAGLIA G., "COMMENTS ON THE PERFECT UNIFORM RANDOM
Packit 67cb25
C                 NUMBER GENERATOR", UNPUBLISHED NOTES, WASH S. U.
Packit 67cb25
C***ROUTINES CALLED  I1MACH,XERROR
Packit 67cb25
C***END PROLOGUE  UNI
Packit 67cb25
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
static inline unsigned long int uni32_get (void *vstate);
Packit 67cb25
static double uni32_get_double (void *vstate);
Packit 67cb25
static void uni32_set (void *state, unsigned long int s);
Packit 67cb25
Packit 67cb25
static const unsigned long int MDIG = 32;       /* Machine digits in int */
Packit 67cb25
static const unsigned long int m1 = 2147483647;         /* 2^(MDIG-1) - 1 */
Packit 67cb25
static const unsigned long int m2 = 65536;      /* 2^(MDIG/2) */
Packit 67cb25
Packit 67cb25
typedef struct
Packit 67cb25
  {
Packit 67cb25
    int i, j;
Packit 67cb25
    unsigned long m[17];
Packit 67cb25
  }
Packit 67cb25
uni32_state_t;
Packit 67cb25
Packit 67cb25
static inline unsigned long
Packit 67cb25
uni32_get (void *vstate)
Packit 67cb25
{
Packit 67cb25
  uni32_state_t *state = (uni32_state_t *) vstate;
Packit 67cb25
  const long int i = state->i;
Packit 67cb25
  const long int j = state->j;
Packit 67cb25
Packit 67cb25
  /* important k not be unsigned */
Packit 67cb25
  long int k = state->m[i] - state->m[j];
Packit 67cb25
Packit 67cb25
  if (k < 0)
Packit 67cb25
    k += m1;
Packit 67cb25
  state->m[j] = k;
Packit 67cb25
Packit 67cb25
  if (i == 0)
Packit 67cb25
    {
Packit 67cb25
      state->i = 16;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      (state->i)--;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (j == 0)
Packit 67cb25
    {
Packit 67cb25
      state->j = 16;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      (state->j)--;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return k;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static double
Packit 67cb25
uni32_get_double (void *vstate)
Packit 67cb25
{
Packit 67cb25
  return uni32_get (vstate) / 2147483647.0 ;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
uni32_set (void *vstate, unsigned long int s)
Packit 67cb25
{
Packit 67cb25
  long int seed, k0, k1, j0, j1;
Packit 67cb25
  int i;
Packit 67cb25
Packit 67cb25
  uni32_state_t *state = (uni32_state_t *) vstate;
Packit 67cb25
Packit 67cb25
  /* For this routine, the seeding is very elaborate! */
Packit 67cb25
  /* A flaw in this approach is that seeds 1,2 give exactly the
Packit 67cb25
     same random number sequence!  */
Packit 67cb25
Packit 67cb25
  /*s = 2*s+1; *//* enforce seed be odd */
Packit 67cb25
  seed = (s < m1 ? s : m1);     /* seed should be less than m1 */
Packit 67cb25
  seed -= (seed % 2 == 0 ? 1 : 0);
Packit 67cb25
Packit 67cb25
  k0 = 9069 % m2;
Packit 67cb25
  k1 = 9069 / m2;
Packit 67cb25
  j0 = seed % m2;
Packit 67cb25
  j1 = seed / m2;
Packit 67cb25
Packit 67cb25
  for (i = 0; i < 17; i++)
Packit 67cb25
    {
Packit 67cb25
      seed = j0 * k0;
Packit 67cb25
      j1 = (seed / m2 + j0 * k1 + j1 * k0) % (m2 / 2);
Packit 67cb25
      j0 = seed % m2;
Packit 67cb25
      state->m[i] = j0 + m2 * j1;
Packit 67cb25
    }
Packit 67cb25
  state->i = 4;
Packit 67cb25
  state->j = 16;
Packit 67cb25
Packit 67cb25
  return;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static const gsl_rng_type uni32_type =
Packit 67cb25
{"uni32",                       /* name */
Packit 67cb25
 2147483646,                    /* RAND_MAX */
Packit 67cb25
 0,                             /* RAND_MIN */
Packit 67cb25
 sizeof (uni32_state_t),
Packit 67cb25
 &uni32_set,
Packit 67cb25
 &uni32_get,
Packit 67cb25
 &uni32_get_double};
Packit 67cb25
Packit 67cb25
const gsl_rng_type *gsl_rng_uni32 = &uni32_type;