New files to implement the Mersenne Twister Pseudo Random Number

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.
This commit is contained in:
Sebastian Wilhelmi 1999-04-09 14:40:58 +00:00 committed by Sebastian Wilhelmi
parent bbc2cc4e0e
commit 95aff22dff
18 changed files with 871 additions and 1 deletions

View File

@ -23,3 +23,8 @@ Sebastian Wilhelmi <wilhelmi@ira.uka.de>
There are also many others who have contributed patches and fixes; There are also many others who have contributed patches and fixes;
we thank them, for helping us in advancing GLIB. 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>

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View 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> Thu Apr 8 21:12:30 CDT 1999 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.3.0 * Released GLib 1.3.0

View File

@ -44,6 +44,7 @@ libglib_la_SOURCES = \
gprimes.c \ gprimes.c \
gqueue.c \ gqueue.c \
grel.c \ grel.c \
grand.c \
gscanner.c \ gscanner.c \
gslist.c \ gslist.c \
gstack.c \ gstack.c \

43
glib.h
View File

@ -2369,6 +2369,49 @@ gpointer g_tuples_index (GTuples *tuples,
gint field); 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. /* Prime numbers.
*/ */

View File

@ -44,6 +44,7 @@ libglib_la_SOURCES = \
gprimes.c \ gprimes.c \
gqueue.c \ gqueue.c \
grel.c \ grel.c \
grand.c \
gscanner.c \ gscanner.c \
gslist.c \ gslist.c \
gstack.c \ gstack.c \

View File

@ -2369,6 +2369,49 @@ gpointer g_tuples_index (GTuples *tuples,
gint field); 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. /* Prime numbers.
*/ */

334
glib/grand.c Normal file
View File

@ -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);
}

334
grand.c Normal file
View File

@ -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);
}

View File

@ -9,6 +9,7 @@ TESTS = \
list-test \ list-test \
node-test \ node-test \
queue-test \ queue-test \
rand-test \
relation-test \ relation-test \
slist-test \ slist-test \
stack-test \ stack-test \
@ -26,6 +27,7 @@ hash_test_LDADD = $(top_builddir)/libglib.la
list_test_LDADD = $(top_builddir)/libglib.la list_test_LDADD = $(top_builddir)/libglib.la
node_test_LDADD = $(top_builddir)/libglib.la node_test_LDADD = $(top_builddir)/libglib.la
queue_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 relation_test_LDADD = $(top_builddir)/libglib.la
slist_test_LDADD = $(top_builddir)/libglib.la slist_test_LDADD = $(top_builddir)/libglib.la
stack_test_LDADD = $(top_builddir)/libglib.la stack_test_LDADD = $(top_builddir)/libglib.la

43
tests/rand-test.c Normal file
View File

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