|
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;
|