New files to implement the Mersenne Twister Pseudo Random Number
authorSebastian Wilhelmi <wilhelmi@ira.uka.de>
Fri, 9 Apr 1999 14:40:58 +0000 (14:40 +0000)
committerSebastian Wilhelmi <wilhelmi@src.gnome.org>
Fri, 9 Apr 1999 14:40:58 +0000 (14:40 +0000)
1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>

* grand.c, tests/rand-test.c: New files to implement the Mersenne
Twister Pseudo Random Number Generator.

* glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
accordingly.

18 files changed:
AUTHORS
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
Makefile.am
glib.h
glib/Makefile.am
glib/glib.h
glib/grand.c [new file with mode: 0644]
grand.c [new file with mode: 0644]
gthread/Makefile.am
tests/Makefile.am
tests/rand-test.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index e898236..49c3037 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -23,3 +23,8 @@ Sebastian Wilhelmi <wilhelmi@ira.uka.de>
 
 There are also many others who have contributed patches and fixes;
 we thank them, for helping us in advancing GLIB.
+
+The random number generator "Mersenne Twister", which is used by GLib,
+is developed and originally coded by:
+Makoto Matsumoto   <matumoto@math.keio.ac.jp>
+Takuji Nishimura   <nisimura@math.keio.ac.jp>
index 87e7995..90d5314 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index 87e7995..90d5314 100644 (file)
@@ -1,3 +1,11 @@
+1999-04-09  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * grand.c, tests/rand-test.c: New files to implement the Mersenne
+       Twister Pseudo Random Number Generator.
+
+       * glib.h, AUTHORS, Makefile.am, tests/Makefile.am: Changed
+       accordingly.
+
 Thu Apr  8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GLib 1.3.0
index bbcb360..32014e4 100644 (file)
@@ -44,6 +44,7 @@ libglib_la_SOURCES = \
        gprimes.c       \
        gqueue.c        \
        grel.c          \
+       grand.c         \
        gscanner.c      \
        gslist.c        \
        gstack.c        \
diff --git a/glib.h b/glib.h
index 01736c2..a772fb5 100644 (file)
--- a/glib.h
+++ b/glib.h
@@ -2369,6 +2369,49 @@ gpointer   g_tuples_index     (GTuples      *tuples,
                               gint         field);
 
 
+/* GRand - a good and fast random number generator: Mersenne Twister 
+ * see http://www.math.keio.ac.jp/~matumoto/emt.html for more info.
+ * The range functions return a value in the intervall [min,max).
+ * int          -> [0..2^32-1]
+ * int_range    -> [min..max-1]
+ * double       -> [0..1)
+ * double_range -> [min..max)
+ */
+
+typedef struct _GRand GRand;
+GRand*  g_rand_new_with_seed   (guint32     seed);
+GRand*  g_rand_new             ();
+void    g_rand_free            (GRand      *rand);
+
+void    g_rand_set_seed        (GRand      *rand, 
+                               guint32     seed);
+guint32 g_rand_int             (GRand      *rand);
+gint32  g_rand_int_range       (GRand      *rand, 
+                               gint32      min, 
+                               gint32      max);
+gdouble g_rand_double          (GRand      *rand);
+gdouble g_rand_double_range    (GRand      *rand, 
+                               gdouble     min, 
+                               gdouble     max);
+/* This might go in, if -lm is no problem for you guys
+gdouble g_rand_normal          (GRand      *rand, 
+                               gdouble     mean, 
+                               gdouble     standard_deviation);
+*/
+
+void    g_random_set_seed      (guint32     seed);
+guint32 g_random_int           ();
+gint32  g_random_int_range     (gint32      min, 
+                               gint32      max);
+gdouble g_random_double        ();
+gdouble g_random_double_range  (gdouble     min, 
+                               gdouble     max);
+/* dito
+gdouble g_random_normal        (gdouble     mean, 
+                               gdouble     standard_deviation);
+*/
+
 /* Prime numbers.
  */
 
index bbcb360..32014e4 100644 (file)
@@ -44,6 +44,7 @@ libglib_la_SOURCES = \
        gprimes.c       \
        gqueue.c        \
        grel.c          \
+       grand.c         \
        gscanner.c      \
        gslist.c        \
        gstack.c        \
index 01736c2..a772fb5 100644 (file)
@@ -2369,6 +2369,49 @@ gpointer   g_tuples_index     (GTuples      *tuples,
                               gint         field);
 
 
+/* GRand - a good and fast random number generator: Mersenne Twister 
+ * see http://www.math.keio.ac.jp/~matumoto/emt.html for more info.
+ * The range functions return a value in the intervall [min,max).
+ * int          -> [0..2^32-1]
+ * int_range    -> [min..max-1]
+ * double       -> [0..1)
+ * double_range -> [min..max)
+ */
+
+typedef struct _GRand GRand;
+GRand*  g_rand_new_with_seed   (guint32     seed);
+GRand*  g_rand_new             ();
+void    g_rand_free            (GRand      *rand);
+
+void    g_rand_set_seed        (GRand      *rand, 
+                               guint32     seed);
+guint32 g_rand_int             (GRand      *rand);
+gint32  g_rand_int_range       (GRand      *rand, 
+                               gint32      min, 
+                               gint32      max);
+gdouble g_rand_double          (GRand      *rand);
+gdouble g_rand_double_range    (GRand      *rand, 
+                               gdouble     min, 
+                               gdouble     max);
+/* This might go in, if -lm is no problem for you guys
+gdouble g_rand_normal          (GRand      *rand, 
+                               gdouble     mean, 
+                               gdouble     standard_deviation);
+*/
+
+void    g_random_set_seed      (guint32     seed);
+guint32 g_random_int           ();
+gint32  g_random_int_range     (gint32      min, 
+                               gint32      max);
+gdouble g_random_double        ();
+gdouble g_random_double_range  (gdouble     min, 
+                               gdouble     max);
+/* dito
+gdouble g_random_normal        (gdouble     mean, 
+                               gdouble     standard_deviation);
+*/
+
 /* Prime numbers.
  */
 
diff --git a/glib/grand.c b/glib/grand.c
new file mode 100644 (file)
index 0000000..2725d9f
--- /dev/null
@@ -0,0 +1,334 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Originally developed and coded by Makoto Matsumoto and Takuji
+ * Nishimura.  Please mail <matumoto@math.keio.ac.jp>, if you're using
+ * code from this file in your own programs or libraries.
+ * Further information on the Mersenne Twister can be found at
+ * http://www.math.keio.ac.jp/~matumoto/emt.html
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.  
+ */
+
+#include <glib.h>
+#include <math.h>
+#include <stdio.h>
+
+G_LOCK_DEFINE_STATIC (global_random);
+static GRand* global_random = NULL;
+
+/* Period parameters */  
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0df   /* constant vector a */
+#define UPPER_MASK 0x80000000 /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffff /* least significant r bits */
+
+/* Tempering parameters */   
+#define TEMPERING_MASK_B 0x9d2c5680
+#define TEMPERING_MASK_C 0xefc60000
+#define TEMPERING_SHIFT_U(y)  (y >> 11)
+#define TEMPERING_SHIFT_S(y)  (y << 7)
+#define TEMPERING_SHIFT_T(y)  (y << 15)
+#define TEMPERING_SHIFT_L(y)  (y >> 18)
+
+struct _GRand
+{
+  guint32 mt[N]; /* the array for the state vector  */
+  guint mti; 
+  gboolean have_next_normal;
+  gdouble next_normal;
+};
+
+GRand*
+g_rand_new_with_seed (guint32 seed)
+{
+  GRand *rand = g_new0 (GRand, 1);
+  g_rand_set_seed (rand, seed);
+  return rand;
+}
+
+GRand* 
+g_rand_new ()
+{
+  guint32 seed = 0;
+  GTimeVal now;
+  FILE* dev_random = fopen("/dev/random", "rb");
+
+  if (dev_random)
+    {
+      if (fread (&seed, sizeof (seed), 1, dev_random) != 1)
+       seed = 0;
+      fclose (dev_random);
+    }
+
+  /* Using /dev/random alone makes the seed computable for the
+     outside. This might pose security problems somewhere. This should
+     yield better values */
+
+  g_get_current_time (&now);
+  seed ^= now.tv_sec ^ now.tv_usec;
+
+  return g_rand_new_with_seed (seed);
+}
+
+void
+g_rand_free (GRand* rand)
+{
+  g_return_if_fail (rand);
+
+  g_free (rand);
+}
+
+void
+g_rand_set_seed (GRand* rand, guint32 seed)
+{
+  g_return_if_fail (rand);
+
+  /* setting initial seeds to mt[N] using         */
+  /* the generator Line 25 of Table 1 in          */
+  /* [KNUTH 1981, The Art of Computer Programming */
+  /*    Vol. 2 (2nd Ed.), pp102]                  */
+  rand->mt[0]= seed & 0xffffffff;
+  for (rand->mti=1; rand->mti<N; rand->mti++)
+    rand->mt[rand->mti] = (69069 * rand->mt[rand->mti-1]) & 0xffffffff;
+
+  rand->have_next_normal = FALSE;
+}
+
+guint32
+g_rand_int (GRand* rand)
+{
+  guint32 y;
+  static const guint32 mag01[2]={0x0, MATRIX_A};
+  /* mag01[x] = x * MATRIX_A  for x=0,1 */
+
+  g_return_val_if_fail (rand, 0);
+
+  if (rand->mti >= N) { /* generate N words at one time */
+    int kk;
+    
+    for (kk=0;kk<N-M;kk++) {
+      y = (rand->mt[kk]&UPPER_MASK)|(rand->mt[kk+1]&LOWER_MASK);
+      rand->mt[kk] = rand->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
+    }
+    for (;kk<N-1;kk++) {
+      y = (rand->mt[kk]&UPPER_MASK)|(rand->mt[kk+1]&LOWER_MASK);
+      rand->mt[kk] = rand->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
+    }
+    y = (rand->mt[N-1]&UPPER_MASK)|(rand->mt[0]&LOWER_MASK);
+    rand->mt[N-1] = rand->mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
+    
+    rand->mti = 0;
+  }
+  
+  y = rand->mt[rand->mti++];
+  y ^= TEMPERING_SHIFT_U(y);
+  y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
+  y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
+  y ^= TEMPERING_SHIFT_L(y);
+  
+  return y; 
+}
+
+gint32 
+g_rand_int_range (GRand* rand, gint32 min, gint32 max)
+{
+  guint32 dist = max - min;
+  guint32 random;
+
+  g_return_val_if_fail (rand, min);
+  g_return_val_if_fail (max > min, min);
+
+  if (dist <= 0x10000L) /* 2^16 */
+    {
+      /* All tricks doing modulo calculations do not have a good
+        distribution -> We must use this slower method for maximal
+        quality, but this method is only good for (max - min) <= 2^16 */
+      
+      random = (gint32) g_rand_double_range (rand, 0, dist);
+      /* we'd rather use the following, if -lm is allowed later on:
+        random = (gint32) floor (g_rand_double_range (rand, 0, dist));  */
+    }
+  else
+    {
+      /* Now it's harder to make it right. We calculate the smallest m,
+         such that dist < 2 ^ m, then we calculate a random number in
+         [1..2^32-1] and rightshift it by 32 - m. Then we test, if it
+         is smaller than dist and if not, get a new number and so
+         forth until we get a number smaller than dist. We just return
+         this. */
+      guint32 border = 0x20000L; /* 2^17 */
+      guint right_shift = 15; /* 32 - 17 */
+
+      if (dist >= 0x80000000) /* in the case of dist > 2^31 our loop
+                               below will be infinite */
+       {
+         right_shift = 0;
+       }
+      else
+       {
+         while (dist >= border) 
+           {
+             border <<= 1;
+             right_shift--;
+           }
+       }
+      do 
+       { 
+         random = g_rand_int (rand) >> right_shift; 
+       } while (random >= dist);
+    }
+  return min + random;
+}
+
+/* transform [0..2^32-1] -> [0..1) */
+#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386963e-10
+
+gdouble 
+g_rand_double (GRand* rand)
+{                            
+  return g_rand_int (rand) * G_RAND_DOUBLE_TRANSFORM;
+}
+
+gdouble 
+g_rand_double_range (GRand* rand, gdouble min, gdouble max)
+{
+  return g_rand_int (rand) * ((max - min) * G_RAND_DOUBLE_TRANSFORM)  + min;
+}
+
+
+#if WE_REALLY_WANT_HAVE_MATH_LIB_LINKED
+gdouble
+g_rand_normal (GRand* rand, gdouble mean, gdouble standard_deviation)
+{
+  /* For a description of the used algorithm see Knuth: "The Art of
+     Computer Programming", Vol.2, Second Edition, Page 117: Polar
+     method for normal deviates due to Box, Muller, Marsaglia */
+  gdouble normal;
+  g_return_val_if_fail (rand, 0);
+
+  if (rand->have_next_normal) 
+    {
+      rand->have_next_normal = FALSE;
+      normal = rand->next_normal;
+    }
+  else
+    {
+      gdouble u1;
+      gdouble u2 = g_rand_double_range (rand, -1, 1); 
+      gdouble s, f;
+      do 
+       { 
+         u1 = u2;
+         u2 = g_rand_double_range (rand, -1, 1);
+         s = u1 * u1 + u2 * u2;
+       } while (s >= 1.0);
+      f = sqrt (-2 * log (s) / s);
+      normal = u1 * f;
+      rand->next_normal = u2 * f;
+      rand->have_next_normal = TRUE;
+    }
+  return mean + normal * standard_deviation;
+}
+#endif
+
+guint32
+g_random_int (void)
+{
+  guint32 result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  
+  result = g_rand_int (global_random);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+gint32 
+g_random_int_range (gint32 min, gint32 max)
+{
+  gint32 result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  
+  result = g_rand_int_range (global_random, min, max);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+gdouble 
+g_random_double (void)
+{
+  double result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  
+  result = g_rand_double (global_random);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+gdouble 
+g_random_double_range (gdouble min, gdouble max)
+{
+  double result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  result = g_rand_double_range (global_random, min, max);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+#if WE_REALLY_WANT_HAVE_MATH_LIB_LINKED
+gdouble
+g_random_normal (gdouble mean, gdouble standard_deviation)
+{
+  double result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  result = g_rand_normal (global_random, mean, standard_deviation);
+  G_UNLOCK (global_random);
+  return result;
+}
+#endif
+
+void
+g_random_set_seed (guint32 seed)
+{
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new_with_seed (seed);
+  else
+    g_rand_set_seed (global_random, seed);
+  G_UNLOCK (global_random);
+}
+
diff --git a/grand.c b/grand.c
new file mode 100644 (file)
index 0000000..2725d9f
--- /dev/null
+++ b/grand.c
@@ -0,0 +1,334 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Originally developed and coded by Makoto Matsumoto and Takuji
+ * Nishimura.  Please mail <matumoto@math.keio.ac.jp>, if you're using
+ * code from this file in your own programs or libraries.
+ * Further information on the Mersenne Twister can be found at
+ * http://www.math.keio.ac.jp/~matumoto/emt.html
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.  
+ */
+
+#include <glib.h>
+#include <math.h>
+#include <stdio.h>
+
+G_LOCK_DEFINE_STATIC (global_random);
+static GRand* global_random = NULL;
+
+/* Period parameters */  
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0df   /* constant vector a */
+#define UPPER_MASK 0x80000000 /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffff /* least significant r bits */
+
+/* Tempering parameters */   
+#define TEMPERING_MASK_B 0x9d2c5680
+#define TEMPERING_MASK_C 0xefc60000
+#define TEMPERING_SHIFT_U(y)  (y >> 11)
+#define TEMPERING_SHIFT_S(y)  (y << 7)
+#define TEMPERING_SHIFT_T(y)  (y << 15)
+#define TEMPERING_SHIFT_L(y)  (y >> 18)
+
+struct _GRand
+{
+  guint32 mt[N]; /* the array for the state vector  */
+  guint mti; 
+  gboolean have_next_normal;
+  gdouble next_normal;
+};
+
+GRand*
+g_rand_new_with_seed (guint32 seed)
+{
+  GRand *rand = g_new0 (GRand, 1);
+  g_rand_set_seed (rand, seed);
+  return rand;
+}
+
+GRand* 
+g_rand_new ()
+{
+  guint32 seed = 0;
+  GTimeVal now;
+  FILE* dev_random = fopen("/dev/random", "rb");
+
+  if (dev_random)
+    {
+      if (fread (&seed, sizeof (seed), 1, dev_random) != 1)
+       seed = 0;
+      fclose (dev_random);
+    }
+
+  /* Using /dev/random alone makes the seed computable for the
+     outside. This might pose security problems somewhere. This should
+     yield better values */
+
+  g_get_current_time (&now);
+  seed ^= now.tv_sec ^ now.tv_usec;
+
+  return g_rand_new_with_seed (seed);
+}
+
+void
+g_rand_free (GRand* rand)
+{
+  g_return_if_fail (rand);
+
+  g_free (rand);
+}
+
+void
+g_rand_set_seed (GRand* rand, guint32 seed)
+{
+  g_return_if_fail (rand);
+
+  /* setting initial seeds to mt[N] using         */
+  /* the generator Line 25 of Table 1 in          */
+  /* [KNUTH 1981, The Art of Computer Programming */
+  /*    Vol. 2 (2nd Ed.), pp102]                  */
+  rand->mt[0]= seed & 0xffffffff;
+  for (rand->mti=1; rand->mti<N; rand->mti++)
+    rand->mt[rand->mti] = (69069 * rand->mt[rand->mti-1]) & 0xffffffff;
+
+  rand->have_next_normal = FALSE;
+}
+
+guint32
+g_rand_int (GRand* rand)
+{
+  guint32 y;
+  static const guint32 mag01[2]={0x0, MATRIX_A};
+  /* mag01[x] = x * MATRIX_A  for x=0,1 */
+
+  g_return_val_if_fail (rand, 0);
+
+  if (rand->mti >= N) { /* generate N words at one time */
+    int kk;
+    
+    for (kk=0;kk<N-M;kk++) {
+      y = (rand->mt[kk]&UPPER_MASK)|(rand->mt[kk+1]&LOWER_MASK);
+      rand->mt[kk] = rand->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
+    }
+    for (;kk<N-1;kk++) {
+      y = (rand->mt[kk]&UPPER_MASK)|(rand->mt[kk+1]&LOWER_MASK);
+      rand->mt[kk] = rand->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
+    }
+    y = (rand->mt[N-1]&UPPER_MASK)|(rand->mt[0]&LOWER_MASK);
+    rand->mt[N-1] = rand->mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
+    
+    rand->mti = 0;
+  }
+  
+  y = rand->mt[rand->mti++];
+  y ^= TEMPERING_SHIFT_U(y);
+  y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
+  y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
+  y ^= TEMPERING_SHIFT_L(y);
+  
+  return y; 
+}
+
+gint32 
+g_rand_int_range (GRand* rand, gint32 min, gint32 max)
+{
+  guint32 dist = max - min;
+  guint32 random;
+
+  g_return_val_if_fail (rand, min);
+  g_return_val_if_fail (max > min, min);
+
+  if (dist <= 0x10000L) /* 2^16 */
+    {
+      /* All tricks doing modulo calculations do not have a good
+        distribution -> We must use this slower method for maximal
+        quality, but this method is only good for (max - min) <= 2^16 */
+      
+      random = (gint32) g_rand_double_range (rand, 0, dist);
+      /* we'd rather use the following, if -lm is allowed later on:
+        random = (gint32) floor (g_rand_double_range (rand, 0, dist));  */
+    }
+  else
+    {
+      /* Now it's harder to make it right. We calculate the smallest m,
+         such that dist < 2 ^ m, then we calculate a random number in
+         [1..2^32-1] and rightshift it by 32 - m. Then we test, if it
+         is smaller than dist and if not, get a new number and so
+         forth until we get a number smaller than dist. We just return
+         this. */
+      guint32 border = 0x20000L; /* 2^17 */
+      guint right_shift = 15; /* 32 - 17 */
+
+      if (dist >= 0x80000000) /* in the case of dist > 2^31 our loop
+                               below will be infinite */
+       {
+         right_shift = 0;
+       }
+      else
+       {
+         while (dist >= border) 
+           {
+             border <<= 1;
+             right_shift--;
+           }
+       }
+      do 
+       { 
+         random = g_rand_int (rand) >> right_shift; 
+       } while (random >= dist);
+    }
+  return min + random;
+}
+
+/* transform [0..2^32-1] -> [0..1) */
+#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386963e-10
+
+gdouble 
+g_rand_double (GRand* rand)
+{                            
+  return g_rand_int (rand) * G_RAND_DOUBLE_TRANSFORM;
+}
+
+gdouble 
+g_rand_double_range (GRand* rand, gdouble min, gdouble max)
+{
+  return g_rand_int (rand) * ((max - min) * G_RAND_DOUBLE_TRANSFORM)  + min;
+}
+
+
+#if WE_REALLY_WANT_HAVE_MATH_LIB_LINKED
+gdouble
+g_rand_normal (GRand* rand, gdouble mean, gdouble standard_deviation)
+{
+  /* For a description of the used algorithm see Knuth: "The Art of
+     Computer Programming", Vol.2, Second Edition, Page 117: Polar
+     method for normal deviates due to Box, Muller, Marsaglia */
+  gdouble normal;
+  g_return_val_if_fail (rand, 0);
+
+  if (rand->have_next_normal) 
+    {
+      rand->have_next_normal = FALSE;
+      normal = rand->next_normal;
+    }
+  else
+    {
+      gdouble u1;
+      gdouble u2 = g_rand_double_range (rand, -1, 1); 
+      gdouble s, f;
+      do 
+       { 
+         u1 = u2;
+         u2 = g_rand_double_range (rand, -1, 1);
+         s = u1 * u1 + u2 * u2;
+       } while (s >= 1.0);
+      f = sqrt (-2 * log (s) / s);
+      normal = u1 * f;
+      rand->next_normal = u2 * f;
+      rand->have_next_normal = TRUE;
+    }
+  return mean + normal * standard_deviation;
+}
+#endif
+
+guint32
+g_random_int (void)
+{
+  guint32 result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  
+  result = g_rand_int (global_random);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+gint32 
+g_random_int_range (gint32 min, gint32 max)
+{
+  gint32 result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  
+  result = g_rand_int_range (global_random, min, max);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+gdouble 
+g_random_double (void)
+{
+  double result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  
+  result = g_rand_double (global_random);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+gdouble 
+g_random_double_range (gdouble min, gdouble max)
+{
+  double result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  result = g_rand_double_range (global_random, min, max);
+  G_UNLOCK (global_random);
+  return result;
+}
+
+#if WE_REALLY_WANT_HAVE_MATH_LIB_LINKED
+gdouble
+g_random_normal (gdouble mean, gdouble standard_deviation)
+{
+  double result;
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new ();
+  result = g_rand_normal (global_random, mean, standard_deviation);
+  G_UNLOCK (global_random);
+  return result;
+}
+#endif
+
+void
+g_random_set_seed (guint32 seed)
+{
+  G_LOCK (global_random);
+  if (!global_random)
+    global_random = g_rand_new_with_seed (seed);
+  else
+    g_rand_set_seed (global_random, seed);
+  G_UNLOCK (global_random);
+}
+
index 2752455..f24dffb 100644 (file)
@@ -22,4 +22,4 @@ libgthread_la_LDFLAGS = \
 libgthread_la_LIBADD = @G_THREAD_LIBS@
 
 noinst_PROGRAMS = testgthread
-testgthread_LDADD = ../libglib.la libgthread.la 
+testgthread_LDADD = ../libglib.la libgthread.la
index 62fcec0..539d2d1 100644 (file)
@@ -9,6 +9,7 @@ TESTS = \
        list-test       \
        node-test       \
        queue-test      \
+       rand-test       \
        relation-test   \
        slist-test      \
        stack-test      \
@@ -26,6 +27,7 @@ hash_test_LDADD = $(top_builddir)/libglib.la
 list_test_LDADD = $(top_builddir)/libglib.la
 node_test_LDADD = $(top_builddir)/libglib.la
 queue_test_LDADD = $(top_builddir)/libglib.la
+rand_test_LDADD = $(top_builddir)/libglib.la
 relation_test_LDADD = $(top_builddir)/libglib.la
 slist_test_LDADD = $(top_builddir)/libglib.la
 stack_test_LDADD = $(top_builddir)/libglib.la
diff --git a/tests/rand-test.c b/tests/rand-test.c
new file mode 100644 (file)
index 0000000..d3af9eb
--- /dev/null
@@ -0,0 +1,43 @@
+#include <glib.h>
+
+const gint32 first_numbers[] = 
+{
+  0x7a7a7a7a,
+  0x20aea82a,
+  0xcab337ab,
+  0xdcf770ea,
+  0xdf552b2f,
+  0x32d1ef7f,
+  0x6bed6dd9,
+  0x7222df44,
+  0x6b842128,
+  0x07f8579a,
+  0x9dad1004,
+  0x2df264f2,
+  0x13b48989,
+  0xf2929475,
+  0x30f30c97,
+  0x3f9a1ea7,
+  0x3bf04710,
+  0xb85bd69e,
+  0x790a48b0,
+  0xfa06b85f,
+  0xa64cc9e3
+};
+
+const gint length = sizeof (first_numbers) / sizeof (first_numbers[0]);
+
+int main()
+{
+  guint i;
+
+  GRand* rand = g_rand_new_with_seed (first_numbers[0]);
+
+  for (i = 1; i < length; i++)
+    g_assert (first_numbers[i]);
+
+  g_rand_free (rand);
+
+  return 0;
+}
+