summaryrefslogtreecommitdiff
path: root/gsl-1.9/rng/ranf.c
blob: cc5ac41b03d250b36eb354201afc31fcea163e25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* rng/ranf.c
 * 
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, Brian Gough
 * 
 * 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; either version 2 of the License, 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 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 02110-1301, USA.
 */

#include <config.h>
#include <math.h>
#include <stdlib.h>
#include <gsl/gsl_rng.h>

/* This is the CRAY RANF generator. The generator returns the
   upper 32 bits from each term of the sequence,

   x_{n+1} = (a x_n) mod m 

   using 48-bit unsigned arithmetic, with a = 0x2875A2E7B175 and m =
   2^48. The seed specifies the lower 32 bits of the initial value,
   x_1, with the lowest bit set (to prevent the seed taking an even
   value), and the upper 16 bits set to 0.

   There is a subtlety in the implementation of the seed. The initial
   state is put one step back by multiplying by the modular inverse of
   a mod m. This is done for compatibility with the original CRAY
   implementation.

   Note, you can only seed the generator with integers up to 2^32,
   while the CRAY uses wide integers which can cover all 2^48 states
   of the generator.

   The theoretical value of x_{10001} is 141091827447341.

   The period of this generator is 2^{46}. */

static inline void ranf_advance (void *vstate);
static unsigned long int ranf_get (void *vstate);
static double ranf_get_double (void *vstate);
static void ranf_set (void *state, unsigned long int s);

static const unsigned short int a0 = 0xB175 ;
static const unsigned short int a1 = 0xA2E7 ;
static const unsigned short int a2 = 0x2875 ;

typedef struct
  {
    unsigned short int x0, x1, x2;
  }
ranf_state_t;

static inline void
ranf_advance (void *vstate)
{
  ranf_state_t *state = (ranf_state_t *) vstate;

  const unsigned long int x0 = (unsigned long int) state->x0 ;
  const unsigned long int x1 = (unsigned long int) state->x1 ;
  const unsigned long int x2 = (unsigned long int) state->x2 ;

  unsigned long int r ;
  
  r = a0 * x0 ;
  state->x0 = (r & 0xFFFF) ;
 
  r >>= 16 ;
  r += a0 * x1 + a1 * x0 ;
  state->x1 = (r & 0xFFFF) ;
  
  r >>= 16 ;
  r += a0 * x2 + a1 * x1 + a2 * x0 ;
  state->x2 = (r & 0xFFFF) ;
}

static unsigned long int 
ranf_get (void *vstate)
{
  unsigned long int x1, x2;

  ranf_state_t *state = (ranf_state_t *) vstate;
  ranf_advance (state) ;  

  x1 = (unsigned long int) state->x1;
  x2 = (unsigned long int) state->x2;
  
  return (x2 << 16) + x1;
}

static double
ranf_get_double (void * vstate)
{
  ranf_state_t *state = (ranf_state_t *) vstate;

  ranf_advance (state) ; 

  return (ldexp((double) state->x2, -16)
          + ldexp((double) state->x1, -32) 
          + ldexp((double) state->x0, -48)) ;
}

static void
ranf_set (void *vstate, unsigned long int s)
{
  ranf_state_t *state = (ranf_state_t *) vstate;

  unsigned short int x0, x1, x2 ;
  unsigned long int r ;

  unsigned long int b0 = 0xD6DD ;
  unsigned long int b1 = 0xB894 ;
  unsigned long int b2 = 0x5CEE ;

  if (s == 0)  /* default seed */
    {
      x0 = 0x9CD1 ;
      x1 = 0x53FC ;
      x2 = 0x9482 ;
    }
  else 
    {
      x0 = (s | 1) & 0xFFFF ;
      x1 = s >> 16 & 0xFFFF ;
      x2 = 0 ;
    }

  r = b0 * x0 ;
  state->x0 = (r & 0xFFFF) ;
 
  r >>= 16 ;
  r += b0 * x1 + b1 * x0 ;
  state->x1 = (r & 0xFFFF) ;
  
  r >>= 16 ;
  r += b0 * x2 + b1 * x1 + b2 * x0 ;
  state->x2 = (r & 0xFFFF) ;

  return;
}

static const gsl_rng_type ranf_type =
{"ranf",                        /* name */
 0xffffffffUL,                  /* RAND_MAX */
 0,                             /* RAND_MIN */
 sizeof (ranf_state_t),
 &ranf_set,
 &ranf_get,
 &ranf_get_double
};

const gsl_rng_type *gsl_rng_ranf = &ranf_type;