summaryrefslogtreecommitdiff
path: root/gsl-1.9/rng/gfsr4.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/rng/gfsr4.c')
-rw-r--r--gsl-1.9/rng/gfsr4.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/gsl-1.9/rng/gfsr4.c b/gsl-1.9/rng/gfsr4.c
new file mode 100644
index 0000000..c3bf594
--- /dev/null
+++ b/gsl-1.9/rng/gfsr4.c
@@ -0,0 +1,165 @@
+/* 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 Foundation, Inc., 59 Temple Place, Suite
+ 330, Boston, MA 02111-1307 USA
+
+ From Robert M. Ziff, "Four-tap shift-register-sequence
+ random-number generators," Computers in Physics 12(4), Jul/Aug
+ 1998, pp 385-392. A generalized feedback shift-register (GFSR)
+ is basically an xor-sum of particular past lagged values. A
+ four-tap register looks like:
+ ra[nd] = ra[nd-A] ^ ra[nd-B] ^ ra[nd-C] ^ ra[nd-D]
+
+ Ziff notes that "it is now widely known" that two-tap registers
+ have serious flaws, the most obvious one being the three-point
+ correlation that comes from the defn of the generator. Nice
+ mathematical properties can be derived for GFSR's, and numerics
+ bears out the claim that 4-tap GFSR's with appropriately chosen
+ offsets are as random as can be measured, using the author's test.
+
+ This implementation uses the values suggested the the author's
+ example on p392, but altered to fit the GSL framework. The "state"
+ is 2^14 longs, or 64Kbytes; 2^14 is the smallest power of two that
+ is larger than D, the largest offset. We really only need a state
+ with the last D values, but by going to a power of two, we can do a
+ masking operation instead of a modulo, and this is presumably
+ faster, though I haven't actually tried it. The article actually
+ suggested a short/fast hack:
+
+ #define RandomInteger (++nd, ra[nd&M]=ra[(nd-A)&M]\
+ ^ra[(nd-B)&M]^ra[(nd-C)&M]^ra[(nd-D)&M])
+
+ so that (as long as you've defined nd,ra[M+1]), then you ca do things
+ like: 'if (RandomInteger < p) {...}'.
+
+ Note that n&M varies from 0 to M, *including* M, so that the
+ array has to be of size M+1. Since M+1 is a power of two, n&M
+ is a potentially quicker implementation of the equivalent n%(M+1).
+
+ This implementation copyright (C) 1998 James Theiler, based on
+ the example mt.c in the GSL, as implemented by Brian Gough.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <gsl/gsl_rng.h>
+
+static inline unsigned long int gfsr4_get (void *vstate);
+static double gfsr4_get_double (void *vstate);
+static void gfsr4_set (void *state, unsigned long int s);
+
+/* Magic numbers */
+#define A 471
+#define B 1586
+#define C 6988
+#define D 9689
+#define M 16383 /* = 2^14-1 */
+/* #define M 0x0003fff */
+
+typedef struct
+ {
+ int nd;
+ unsigned long ra[M+1];
+ }
+gfsr4_state_t;
+
+static inline unsigned long
+gfsr4_get (void *vstate)
+{
+ gfsr4_state_t *state = (gfsr4_state_t *) vstate;
+
+ state->nd = ((state->nd)+1)&M;
+ return state->ra[(state->nd)] =
+ state->ra[((state->nd)+(M+1-A))&M]^
+ state->ra[((state->nd)+(M+1-B))&M]^
+ state->ra[((state->nd)+(M+1-C))&M]^
+ state->ra[((state->nd)+(M+1-D))&M];
+
+}
+
+static double
+gfsr4_get_double (void * vstate)
+{
+ return gfsr4_get (vstate) / 4294967296.0 ;
+}
+
+static void
+gfsr4_set (void *vstate, unsigned long int s)
+{
+ gfsr4_state_t *state = (gfsr4_state_t *) vstate;
+ int i, j;
+ /* Masks for turning on the diagonal bit and turning off the
+ leftmost bits */
+ unsigned long int msb = 0x80000000UL;
+ unsigned long int mask = 0xffffffffUL;
+
+ if (s == 0)
+ s = 4357; /* the default seed is 4357 */
+
+ /* We use the congruence s_{n+1} = (69069*s_n) mod 2^32 to
+ initialize the state. This works because ANSI-C unsigned long
+ integer arithmetic is automatically modulo 2^32 (or a higher
+ power of two), so we can safely ignore overflow. */
+
+#define LCG(n) ((69069 * n) & 0xffffffffUL)
+
+ /* Brian Gough suggests this to avoid low-order bit correlations */
+ for (i = 0; i <= M; i++)
+ {
+ unsigned long t = 0 ;
+ unsigned long bit = msb ;
+ for (j = 0; j < 32; j++)
+ {
+ s = LCG(s) ;
+ if (s & msb)
+ t |= bit ;
+ bit >>= 1 ;
+ }
+ state->ra[i] = t ;
+ }
+
+ /* Perform the "orthogonalization" of the matrix */
+ /* Based on the orthogonalization used in r250, as suggested initially
+ * by Kirkpatrick and Stoll, and pointed out to me by Brian Gough
+ */
+
+ /* BJG: note that this orthogonalisation doesn't have any effect
+ here because the the initial 6695 elements do not participate in
+ the calculation. For practical purposes this orthogonalisation
+ is somewhat irrelevant, because the probability of the original
+ sequence being degenerate should be exponentially small. */
+
+ for (i=0; i<32; ++i) {
+ int k=7+i*3;
+ state->ra[k] &= mask; /* Turn off bits left of the diagonal */
+ state->ra[k] |= msb; /* Turn on the diagonal bit */
+ mask >>= 1;
+ msb >>= 1;
+ }
+
+ state->nd = i;
+}
+
+static const gsl_rng_type gfsr4_type =
+{"gfsr4", /* name */
+ 0xffffffffUL, /* RAND_MAX */
+ 0, /* RAND_MIN */
+ sizeof (gfsr4_state_t),
+ &gfsr4_set,
+ &gfsr4_get,
+ &gfsr4_get_double};
+
+const gsl_rng_type *gsl_rng_gfsr4 = &gfsr4_type;
+
+
+
+
+