+Fri Dec 19 11:49:21 2003 George Lebl <jirka@5z.com>
+
+ * glib/grand.c
+ glib/grand.h (g_rand_new) (g_rand_new_with_seed)
+ (g_rand_new_with_seed_array) (g_rand_set_seed_array): Add
+ the init_by_array functionality from the reference implementation
+ of the mersenne twister (mt19937ar.c) and change the naming
+ to fit with the rest of the grand API. New functions are
+ g_rand_new_with_seed_array, g_rand_set_seed_array. This is only
+ reliable/tested for the 2.2 version of the seeding as that's what
+ the reference implementation uses. Also modify g_rand_new to
+ get 4 longs from /dev/urandom since that will always be available
+ anyway and we get more entropy and if /dev/urandom is unavailable
+ use also 4 longs for seeding using secs, usecs, getpid and getppid.
+ For version 2.0 use only a simple seed again but be more careful
+ about seeding with secs/usecs in this case.
+
+ * glib/grand.c
+ glib/grand.h (g_rand_copy): Add g_rand_copy function to copy the
+ current state of the random number generator.
+
+ * glib/grand.c (g_rand_new): Add testing for EINTR when reading
+ from /dev/urandom
+
+ * tests/rand-test.c: add testing of the array seeding stuff against
+ the reference implementation, plus add statistical sanity check
+ to see that the values outputted are truly kind of random. And
+ check that g_rand_copy truly copies the state by checking a few
+ terms.
+
Tue Jan 6 15:38:30 2004 Owen Taylor <otaylor@redhat.com>
* glib/gutils.h: Check defined (__OPTIMIZE__) not
+Fri Dec 19 11:49:21 2003 George Lebl <jirka@5z.com>
+
+ * glib/grand.c
+ glib/grand.h (g_rand_new) (g_rand_new_with_seed)
+ (g_rand_new_with_seed_array) (g_rand_set_seed_array): Add
+ the init_by_array functionality from the reference implementation
+ of the mersenne twister (mt19937ar.c) and change the naming
+ to fit with the rest of the grand API. New functions are
+ g_rand_new_with_seed_array, g_rand_set_seed_array. This is only
+ reliable/tested for the 2.2 version of the seeding as that's what
+ the reference implementation uses. Also modify g_rand_new to
+ get 4 longs from /dev/urandom since that will always be available
+ anyway and we get more entropy and if /dev/urandom is unavailable
+ use also 4 longs for seeding using secs, usecs, getpid and getppid.
+ For version 2.0 use only a simple seed again but be more careful
+ about seeding with secs/usecs in this case.
+
+ * glib/grand.c
+ glib/grand.h (g_rand_copy): Add g_rand_copy function to copy the
+ current state of the random number generator.
+
+ * glib/grand.c (g_rand_new): Add testing for EINTR when reading
+ from /dev/urandom
+
+ * tests/rand-test.c: add testing of the array seeding stuff against
+ the reference implementation, plus add statistical sanity check
+ to see that the values outputted are truly kind of random. And
+ check that g_rand_copy truly copies the state by checking a few
+ terms.
+
Tue Jan 6 15:38:30 2004 Owen Taylor <otaylor@redhat.com>
* glib/gutils.h: Check defined (__OPTIMIZE__) not
+Fri Dec 19 11:49:21 2003 George Lebl <jirka@5z.com>
+
+ * glib/grand.c
+ glib/grand.h (g_rand_new) (g_rand_new_with_seed)
+ (g_rand_new_with_seed_array) (g_rand_set_seed_array): Add
+ the init_by_array functionality from the reference implementation
+ of the mersenne twister (mt19937ar.c) and change the naming
+ to fit with the rest of the grand API. New functions are
+ g_rand_new_with_seed_array, g_rand_set_seed_array. This is only
+ reliable/tested for the 2.2 version of the seeding as that's what
+ the reference implementation uses. Also modify g_rand_new to
+ get 4 longs from /dev/urandom since that will always be available
+ anyway and we get more entropy and if /dev/urandom is unavailable
+ use also 4 longs for seeding using secs, usecs, getpid and getppid.
+ For version 2.0 use only a simple seed again but be more careful
+ about seeding with secs/usecs in this case.
+
+ * glib/grand.c
+ glib/grand.h (g_rand_copy): Add g_rand_copy function to copy the
+ current state of the random number generator.
+
+ * glib/grand.c (g_rand_new): Add testing for EINTR when reading
+ from /dev/urandom
+
+ * tests/rand-test.c: add testing of the array seeding stuff against
+ the reference implementation, plus add statistical sanity check
+ to see that the values outputted are truly kind of random. And
+ check that g_rand_copy truly copies the state by checking a few
+ terms.
+
Tue Jan 6 15:38:30 2004 Owen Taylor <otaylor@redhat.com>
* glib/gutils.h: Check defined (__OPTIMIZE__) not
+Fri Dec 19 11:49:21 2003 George Lebl <jirka@5z.com>
+
+ * glib/grand.c
+ glib/grand.h (g_rand_new) (g_rand_new_with_seed)
+ (g_rand_new_with_seed_array) (g_rand_set_seed_array): Add
+ the init_by_array functionality from the reference implementation
+ of the mersenne twister (mt19937ar.c) and change the naming
+ to fit with the rest of the grand API. New functions are
+ g_rand_new_with_seed_array, g_rand_set_seed_array. This is only
+ reliable/tested for the 2.2 version of the seeding as that's what
+ the reference implementation uses. Also modify g_rand_new to
+ get 4 longs from /dev/urandom since that will always be available
+ anyway and we get more entropy and if /dev/urandom is unavailable
+ use also 4 longs for seeding using secs, usecs, getpid and getppid.
+ For version 2.0 use only a simple seed again but be more careful
+ about seeding with secs/usecs in this case.
+
+ * glib/grand.c
+ glib/grand.h (g_rand_copy): Add g_rand_copy function to copy the
+ current state of the random number generator.
+
+ * glib/grand.c (g_rand_new): Add testing for EINTR when reading
+ from /dev/urandom
+
+ * tests/rand-test.c: add testing of the array seeding stuff against
+ the reference implementation, plus add statistical sanity check
+ to see that the values outputted are truly kind of random. And
+ check that g_rand_copy truly copies the state by checking a few
+ terms.
+
Tue Jan 6 15:38:30 2004 Owen Taylor <otaylor@redhat.com>
* glib/gutils.h: Check defined (__OPTIMIZE__) not
+Fri Dec 19 11:49:21 2003 George Lebl <jirka@5z.com>
+
+ * glib/grand.c
+ glib/grand.h (g_rand_new) (g_rand_new_with_seed)
+ (g_rand_new_with_seed_array) (g_rand_set_seed_array): Add
+ the init_by_array functionality from the reference implementation
+ of the mersenne twister (mt19937ar.c) and change the naming
+ to fit with the rest of the grand API. New functions are
+ g_rand_new_with_seed_array, g_rand_set_seed_array. This is only
+ reliable/tested for the 2.2 version of the seeding as that's what
+ the reference implementation uses. Also modify g_rand_new to
+ get 4 longs from /dev/urandom since that will always be available
+ anyway and we get more entropy and if /dev/urandom is unavailable
+ use also 4 longs for seeding using secs, usecs, getpid and getppid.
+ For version 2.0 use only a simple seed again but be more careful
+ about seeding with secs/usecs in this case.
+
+ * glib/grand.c
+ glib/grand.h (g_rand_copy): Add g_rand_copy function to copy the
+ current state of the random number generator.
+
+ * glib/grand.c (g_rand_new): Add testing for EINTR when reading
+ from /dev/urandom
+
+ * tests/rand-test.c: add testing of the array seeding stuff against
+ the reference implementation, plus add statistical sanity check
+ to see that the values outputted are truly kind of random. And
+ check that g_rand_copy truly copies the state by checking a few
+ terms.
+
Tue Jan 6 15:38:30 2004 Owen Taylor <otaylor@redhat.com>
* glib/gutils.h: Check defined (__OPTIMIZE__) not
+Fri Dec 19 11:49:21 2003 George Lebl <jirka@5z.com>
+
+ * glib/grand.c
+ glib/grand.h (g_rand_new) (g_rand_new_with_seed)
+ (g_rand_new_with_seed_array) (g_rand_set_seed_array): Add
+ the init_by_array functionality from the reference implementation
+ of the mersenne twister (mt19937ar.c) and change the naming
+ to fit with the rest of the grand API. New functions are
+ g_rand_new_with_seed_array, g_rand_set_seed_array. This is only
+ reliable/tested for the 2.2 version of the seeding as that's what
+ the reference implementation uses. Also modify g_rand_new to
+ get 4 longs from /dev/urandom since that will always be available
+ anyway and we get more entropy and if /dev/urandom is unavailable
+ use also 4 longs for seeding using secs, usecs, getpid and getppid.
+ For version 2.0 use only a simple seed again but be more careful
+ about seeding with secs/usecs in this case.
+
+ * glib/grand.c
+ glib/grand.h (g_rand_copy): Add g_rand_copy function to copy the
+ current state of the random number generator.
+
+ * glib/grand.c (g_rand_new): Add testing for EINTR when reading
+ from /dev/urandom
+
+ * tests/rand-test.c: add testing of the array seeding stuff against
+ the reference implementation, plus add statistical sanity check
+ to see that the values outputted are truly kind of random. And
+ check that g_rand_copy truly copies the state by checking a few
+ terms.
+
Tue Jan 6 15:38:30 2004 Owen Taylor <otaylor@redhat.com>
* glib/gutils.h: Check defined (__OPTIMIZE__) not
#include "config.h"
#include <math.h>
+#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "glib.h"
#include "gthreadinit.h"
}
/**
+ * g_rand_new_with_seed_array:
+ * @seed: an array of seeds to initialize the random number generator.
+ * @seed_length: an array of seeds to initialize the random number generator.
+ *
+ * Creates a new random number generator initialized with @seed.
+ *
+ * Return value: the new #GRand.
+ **/
+GRand*
+g_rand_new_with_seed_array (const guint32 *seed, guint seed_length)
+{
+ GRand *rand = g_new0 (GRand, 1);
+ g_rand_set_seed_array (rand, seed, seed_length);
+ return rand;
+}
+
+/**
* g_rand_new:
*
* Creates a new random number generator initialized with a seed taken
GRand*
g_rand_new (void)
{
- guint32 seed;
+ guint32 seed[4];
GTimeVal now;
#ifdef G_OS_UNIX
static gboolean dev_urandom_exists = TRUE;
if (dev_urandom_exists)
{
- FILE* dev_urandom = fopen("/dev/urandom", "rb");
+ FILE* dev_urandom;
+
+ do
+ {
+ errno = 0;
+ dev_urandom = fopen("/dev/urandom", "rb");
+ }
+ while G_UNLIKELY (errno == EINTR);
+
if (dev_urandom)
{
- if (fread (&seed, sizeof (seed), 1, dev_urandom) != 1)
+ int r;
+
+ do
+ {
+ errno = 0;
+ r = fread (seed, sizeof (seed), 1, dev_urandom);
+ }
+ while G_UNLIKELY (errno == EINTR);
+
+ if (r != 1)
dev_urandom_exists = FALSE;
- fclose (dev_urandom);
+
+ do
+ {
+ errno = 0;
+ fclose (dev_urandom);
+ }
+ while G_UNLIKELY (errno == EINTR);
}
else
dev_urandom_exists = FALSE;
if (!dev_urandom_exists)
{
g_get_current_time (&now);
- seed = now.tv_sec ^ now.tv_usec;
+ seed[0] = now.tv_sec;
+ seed[1] = now.tv_usec;
+ seed[2] = getpid ();
+ seed[3] = getppid ();
}
- return g_rand_new_with_seed (seed);
+ return g_rand_new_with_seed_array (seed, 4);
}
/**
}
/**
+ * g_rand_copy:
+ * @rand_: a #GRand.
+ *
+ * Copies a #GRand into a new one with the same exact state as before.
+ * This way you can take a snapshot of the random number generator for
+ * replaying later.
+ *
+ * Return value: the new #GRand.
+ **/
+GRand *
+g_rand_copy (GRand* rand)
+{
+ GRand* new_rand;
+
+ g_return_val_if_fail (rand != NULL, NULL);
+
+ new_rand = g_new0 (GRand, 1);
+ memcpy (new_rand, rand, sizeof (GRand));
+
+ return new_rand;
+}
+
+/**
* g_rand_set_seed:
* @rand_: a #GRand.
* @seed: a value to reinitialize the random number generator.
}
/**
+ * g_rand_set_seed_array:
+ * @rand_: a #GRand.
+ * @seed: array to initialize with
+ * @seed_length: length of array
+ *
+ * Initializes the random number generator by an array of
+ * longs. Array can be of arbitrary size, though only the
+ * first 624 values are taken. This function is useful
+ * if you have many low entropy seeds, or if you require more then
+ * 32bits of actual entropy for your application.
+ **/
+void
+g_rand_set_seed_array (GRand* rand, const guint32 *seed, guint seed_length)
+{
+ int i, j, k;
+
+ g_return_if_fail (rand != NULL);
+ g_return_if_fail (seed_length >= 1);
+
+ g_rand_set_seed (rand, 19650218UL);
+
+ i=1; j=0;
+ k = (N>seed_length ? N : seed_length);
+ for (; k; k--)
+ {
+ rand->mt[i] = (rand->mt[i] ^
+ ((rand->mt[i-1] ^ (rand->mt[i-1] >> 30)) * 1664525UL))
+ + seed[j] + j; /* non linear */
+ rand->mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+ i++; j++;
+ if (i>=N)
+ {
+ rand->mt[0] = rand->mt[N-1];
+ i=1;
+ }
+ if (j>=seed_length)
+ j=0;
+ }
+ for (k=N-1; k; k--)
+ {
+ rand->mt[i] = (rand->mt[i] ^
+ ((rand->mt[i-1] ^ (rand->mt[i-1] >> 30)) * 1566083941UL))
+ - i; /* non linear */
+ rand->mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+ i++;
+ if (i>=N)
+ {
+ rand->mt[0] = rand->mt[N-1];
+ i=1;
+ }
+ }
+
+ rand->mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
+}
+
+/**
* g_rand_int:
* @rand_: a #GRand.
*
*/
GRand* g_rand_new_with_seed (guint32 seed);
+GRand* g_rand_new_with_seed_array (const guint32 *seed,
+ guint seed_length);
GRand* g_rand_new (void);
void g_rand_free (GRand *rand_);
+GRand* g_rand_copy (GRand *rand_);
void g_rand_set_seed (GRand *rand_,
guint32 seed);
+void g_rand_set_seed_array (GRand *rand_,
+ const guint32 *seed,
+ guint seed_length);
#define g_rand_boolean(rand_) ((g_rand_int (rand_) & (1 << 15)) != 0)
#include <glib.h>
-const gint32 first_numbers[] =
+/* Outputs tested against the reference implementation mt19937ar.c from
+ http://www.math.keio.ac.jp/~matumoto/MT2002/emt19937ar.html */
+
+/* Tests for a simple seed, first number is the seed */
+const guint32 first_numbers[] =
{
0x7a7a7a7a,
0xfdcc2d54,
0x1696330c,
};
+/* array seed */
+const guint32 seed_array[] =
+{
+ 0x6553375f,
+ 0xd6b8d43b,
+ 0xa1e7667f,
+ 0x2b10117c
+};
+
+/* tests for the array seed */
+const guint32 array_outputs[] =
+{
+ 0xc22b7dc3,
+ 0xfdecb8ae,
+ 0xb4af0738,
+ 0x516bc6e1,
+ 0x7e372e91,
+ 0x2d38ff80,
+ 0x6096494a,
+ 0xd162d5a8,
+ 0x3c0aaa0d,
+ 0x10e736ae
+};
+
const gint length = sizeof (first_numbers) / sizeof (first_numbers[0]);
+const gint seed_length = sizeof (seed_array) / sizeof (seed_array[0]);
+const gint array_length = sizeof (array_outputs) / sizeof (array_outputs[0]);
int main()
{
guint n;
+ guint ones;
+ double proportion;
GRand* rand = g_rand_new_with_seed (first_numbers[0]);
+ GRand* copy;
for (n = 1; n < length; n++)
g_assert (first_numbers[n] == g_rand_int (rand));
+ g_rand_set_seed (rand, 2);
+ g_rand_set_seed_array (rand, seed_array, seed_length);
+
+ for (n = 0; n < array_length; n++)
+ g_assert (array_outputs[n] == g_rand_int (rand));
+
+ copy = g_rand_copy (rand);
+ for (n = 0; n < 100; n++)
+ g_assert (g_rand_int (copy) == g_rand_int (rand));
+
for (n = 1; n < 100000; n++)
{
gint32 i;
g_assert (b == TRUE || b == FALSE);
}
+ /* Statistical sanity check, count the number of ones
+ * when getting random numbers in range [0,3) and see
+ * that it must be semi-close to 0.25 with a VERY large
+ * probability */
+ ones = 0;
+ for (n = 1; n < 100000; n++)
+ {
+ if (g_random_int_range (0, 4) == 1)
+ ones ++;
+ }
+ proportion = (double)ones / (double)100000;
+ /* 0.025 is overkill, but should suffice to test for some unreasonability */
+ g_assert (ABS (proportion - 0.25) < 0.025);
+
g_rand_free (rand);
+ g_rand_free (copy);
return 0;
}