X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgrand.c;h=6262cd21b79332354d9b99e236a72d9a22104913;hb=30ed5f53e205e6bfc35126a9d3c62dac8a9c5dad;hp=1a998930aee300ec5154c21b9f00d1192e54f438;hpb=d85b722734a6fcfe94032f6113de9e5c190fd7c3;p=platform%2Fupstream%2Fglib.git diff --git a/glib/grand.c b/glib/grand.c index 1a99893..6262cd2 100644 --- a/glib/grand.c +++ b/glib/grand.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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. + * License along with this library; if not, see . */ /* Originally developed and coded by Makoto Matsumoto and Takuji @@ -37,16 +35,13 @@ */ #include "config.h" +#define _CRT_RAND_S #include #include #include #include #include -#ifdef HAVE_UNISTD_H -#include -#endif - #include "grand.h" #include "genviron.h" @@ -55,8 +50,12 @@ #include "gtestutils.h" #include "gthread.h" +#ifdef G_OS_UNIX +#include +#endif + #ifdef G_OS_WIN32 -#include /* For getpid() */ +#include #endif /** @@ -65,52 +64,59 @@ * @short_description: pseudo-random number generator * * The following functions allow you to use a portable, fast and good - * pseudo-random number generator (PRNG). It uses the Mersenne Twister - * PRNG, which was originally developed by Makoto Matsumoto and Takuji - * Nishimura. Further information can be found at - * - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html. - * - * If you just need a random number, you simply call the - * g_random_* functions, which will create a - * globally used #GRand and use the according - * g_rand_* functions internally. Whenever you - * need a stream of reproducible random numbers, you better create a - * #GRand yourself and use the g_rand_* functions - * directly, which will also be slightly faster. Initializing a #GRand - * with a certain seed will produce exactly the same series of random - * numbers on all platforms. This can thus be used as a seed for e.g. - * games. - * - * The g_rand*_range functions will return high - * quality equally distributed random numbers, whereas for example the - * (g_random_int()%max) approach often + * pseudo-random number generator (PRNG). + * + * Do not use this API for cryptographic purposes such as key + * generation, nonces, salts or one-time pads. + * + * This PRNG is suitable for non-cryptographic use such as in games + * (shuffling a card deck, generating levels), generating data for + * a test suite, etc. If you need random data for cryptographic + * purposes, it is recommended to use platform-specific APIs such + * as `/dev/random` on UNIX, or CryptGenRandom() on Windows. + * + * GRand uses the Mersenne Twister PRNG, which was originally + * developed by Makoto Matsumoto and Takuji Nishimura. Further + * information can be found at + * [this page](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html). + * + * If you just need a random number, you simply call the g_random_* + * functions, which will create a globally used #GRand and use the + * according g_rand_* functions internally. Whenever you need a + * stream of reproducible random numbers, you better create a + * #GRand yourself and use the g_rand_* functions directly, which + * will also be slightly faster. Initializing a #GRand with a + * certain seed will produce exactly the same series of random + * numbers on all platforms. This can thus be used as a seed for + * e.g. games. + * + * The g_rand*_range functions will return high quality equally + * distributed random numbers, whereas for example the + * `(g_random_int()%max)` approach often * doesn't yield equally distributed numbers. * * GLib changed the seeding algorithm for the pseudo-random number - * generator Mersenne Twister, as used by - * GRand and GRandom. - * This was necessary, because some seeds would yield very bad - * pseudo-random streams. Also the pseudo-random integers generated by - * g_rand*_int_range() will have a slightly better - * equal distribution with the new version of GLib. - * - * The original seeding and generation algorithms, as found in GLib - * 2.0.x, can be used instead of the new ones by setting the - * environment variable G_RANDOM_VERSION to the value of - * '2.0'. Use the GLib-2.0 algorithms only if you have sequences of - * numbers generated with Glib-2.0 that you need to reproduce exactly. - **/ + * generator Mersenne Twister, as used by #GRand. This was necessary, + * because some seeds would yield very bad pseudo-random streams. + * Also the pseudo-random integers generated by g_rand*_int_range() + * will have a slightly better equal distribution with the new + * version of GLib. + * + * The original seeding and generation algorithms, as found in + * GLib 2.0.x, can be used instead of the new ones by setting the + * environment variable `G_RANDOM_VERSION` to the value of '2.0'. + * Use the GLib-2.0 algorithms only if you have sequences of numbers + * generated with Glib-2.0 that you need to reproduce exactly. + */ /** * GRand: * - * The #GRand struct is an opaque data structure. It should only be - * accessed through the g_rand_* functions. + * The GRand struct is an opaque data structure. It should only be + * accessed through the g_rand_* functions. **/ G_LOCK_DEFINE_STATIC (global_random); -static GRand* global_random = NULL; /* Period parameters */ #define N 624 @@ -161,11 +167,11 @@ struct _GRand /** * g_rand_new_with_seed: - * @seed: a value to initialize the random number generator. + * @seed: a value to initialize the random number generator * * Creates a new random number generator initialized with @seed. * - * Return value: the new #GRand. + * Returns: the new #GRand **/ GRand* g_rand_new_with_seed (guint32 seed) @@ -177,17 +183,19 @@ g_rand_new_with_seed (guint32 seed) /** * 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. + * @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. + * Returns: the new #GRand * * Since: 2.4 - **/ + */ GRand* -g_rand_new_with_seed_array (const guint32 *seed, guint seed_length) +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); @@ -198,29 +206,30 @@ g_rand_new_with_seed_array (const guint32 *seed, guint seed_length) * g_rand_new: * * Creates a new random number generator initialized with a seed taken - * either from /dev/urandom (if existing) or from - * the current time (as a fallback). + * either from `/dev/urandom` (if existing) or from the current time + * (as a fallback). + * + * On Windows, the seed is taken from rand_s(). * - * Return value: the new #GRand. - **/ + * Returns: the new #GRand + */ GRand* g_rand_new (void) { guint32 seed[4]; - GTimeVal now; #ifdef G_OS_UNIX static gboolean dev_urandom_exists = TRUE; + GTimeVal now; if (dev_urandom_exists) { FILE* dev_urandom; do - { - errno = 0; + { dev_urandom = fopen("/dev/urandom", "rb"); } - while G_UNLIKELY (errno == EINTR); + while G_UNLIKELY (dev_urandom == NULL && errno == EINTR); if (dev_urandom) { @@ -242,9 +251,6 @@ g_rand_new (void) else dev_urandom_exists = FALSE; } -#else - static gboolean dev_urandom_exists = FALSE; -#endif if (!dev_urandom_exists) { @@ -252,24 +258,26 @@ g_rand_new (void) seed[0] = now.tv_sec; seed[1] = now.tv_usec; seed[2] = getpid (); -#ifdef G_OS_UNIX seed[3] = getppid (); -#else - seed[3] = 0; -#endif } +#else /* G_OS_WIN32 */ + gint i; + + for (i = 0; i < G_N_ELEMENTS (seed); i++) + rand_s (&seed[i]); +#endif return g_rand_new_with_seed_array (seed, 4); } /** * g_rand_free: - * @rand_: a #GRand. + * @rand_: a #GRand * * Frees the memory allocated for the #GRand. - **/ + */ void -g_rand_free (GRand* rand) +g_rand_free (GRand *rand) { g_return_if_fail (rand != NULL); @@ -278,18 +286,18 @@ g_rand_free (GRand* rand) /** * g_rand_copy: - * @rand_: a #GRand. + * @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. + * Returns: the new #GRand * * Since: 2.4 - **/ -GRand * -g_rand_copy (GRand* rand) + */ +GRand* +g_rand_copy (GRand *rand) { GRand* new_rand; @@ -303,13 +311,14 @@ g_rand_copy (GRand* rand) /** * g_rand_set_seed: - * @rand_: a #GRand. - * @seed: a value to reinitialize the random number generator. + * @rand_: a #GRand + * @seed: a value to reinitialize the random number generator * * Sets the seed for the random number generator #GRand to @seed. - **/ + */ void -g_rand_set_seed (GRand* rand, guint32 seed) +g_rand_set_seed (GRand *rand, + guint32 seed) { g_return_if_fail (rand != NULL); @@ -321,7 +330,7 @@ g_rand_set_seed (GRand* rand, guint32 seed) /* [KNUTH 1981, The Art of Computer Programming */ /* Vol. 2 (2nd Ed.), pp102] */ - if (seed == 0) /* This would make the PRNG procude only zeros */ + if (seed == 0) /* This would make the PRNG produce only zeros */ seed = 0x6b842128; /* Just set it to another number */ rand->mt[0]= seed; @@ -346,20 +355,22 @@ g_rand_set_seed (GRand* rand, guint32 seed) /** * g_rand_set_seed_array: - * @rand_: a #GRand. + * @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. + * 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 32 bits of actual entropy for + * your application. * * Since: 2.4 - **/ + */ void -g_rand_set_seed_array (GRand* rand, const guint32 *seed, guint seed_length) +g_rand_set_seed_array (GRand *rand, + const guint32 *seed, + guint seed_length) { int i, j, k; @@ -404,23 +415,24 @@ g_rand_set_seed_array (GRand* rand, const guint32 *seed, guint seed_length) /** * g_rand_boolean: - * @rand_: a #GRand. - * @Returns: a random #gboolean. + * @rand_: a #GRand * - * Returns a random #gboolean from @rand_. This corresponds to a - * unbiased coin toss. - **/ + * Returns a random #gboolean from @rand_. + * This corresponds to a unbiased coin toss. + * + * Returns: a random #gboolean + */ /** * g_rand_int: - * @rand_: a #GRand. + * @rand_: a #GRand * * Returns the next random #guint32 from @rand_ equally distributed over * the range [0..2^32-1]. * - * Return value: A random number. - **/ + * Returns: a random number + */ guint32 -g_rand_int (GRand* rand) +g_rand_int (GRand *rand) { guint32 y; static const guint32 mag01[2]={0x0, MATRIX_A}; @@ -431,11 +443,11 @@ g_rand_int (GRand* rand) if (rand->mti >= N) { /* generate N words at one time */ int kk; - for (kk=0;kkmt[kk]&UPPER_MASK)|(rand->mt[kk+1]&LOWER_MASK); rand->mt[kk] = rand->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]; } - for (;kkmt[kk]&UPPER_MASK)|(rand->mt[kk+1]&LOWER_MASK); rand->mt[kk] = rand->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]; } @@ -459,17 +471,19 @@ g_rand_int (GRand* rand) /** * g_rand_int_range: - * @rand_: a #GRand. - * @begin: lower closed bound of the interval. - * @end: upper open bound of the interval. + * @rand_: a #GRand + * @begin: lower closed bound of the interval + * @end: upper open bound of the interval * * Returns the next random #gint32 from @rand_ equally distributed over * the range [@begin..@end-1]. * - * Return value: A random number. - **/ + * Returns: a random number + */ gint32 -g_rand_int_range (GRand* rand, gint32 begin, gint32 end) +g_rand_int_range (GRand *rand, + gint32 begin, + gint32 end) { guint32 dist = end - begin; guint32 random; @@ -484,9 +498,9 @@ g_rand_int_range (GRand* rand, gint32 begin, gint32 end) { /* This method, which only calls g_rand_int once is only good * for (end - begin) <= 2^16, because we only have 32 bits set - * from the one call to g_rand_int (). */ - - /* we are using (trans + trans * trans), because g_rand_int only + * from the one call to g_rand_int (). + * + * We are using (trans + trans * trans), because g_rand_int only * covers [0..2^32-1] and thus g_rand_int * trans only covers * [0..1-2^-32], but the biggest double < 1 is 1-2^-52. */ @@ -499,9 +513,10 @@ g_rand_int_range (GRand* rand, gint32 begin, gint32 end) } else { - /* Now we use g_rand_double_range (), which will set 52 bits for - us, so that it is safe to round and still get a decent - distribution */ + /* Now we use g_rand_double_range (), which will set 52 bits + * for us, so that it is safe to round and still get a decent + * distribution + */ random = (gint32) g_rand_double_range (rand, 0, dist); } break; @@ -511,7 +526,8 @@ g_rand_int_range (GRand* rand, gint32 begin, gint32 end) else { /* maxvalue is set to the predecessor of the greatest - * multiple of dist less or equal 2^32. */ + * multiple of dist less or equal 2^32. + */ guint32 maxvalue; if (dist <= 0x80000000u) /* 2^31 */ { @@ -540,15 +556,15 @@ g_rand_int_range (GRand* rand, gint32 begin, gint32 end) /** * g_rand_double: - * @rand_: a #GRand. + * @rand_: a #GRand * * Returns the next random #gdouble from @rand_ equally distributed over * the range [0..1). * - * Return value: A random number. - **/ + * Returns: a random number + */ gdouble -g_rand_double (GRand* rand) +g_rand_double (GRand *rand) { /* We set all 52 bits after the point for this, not only the first 32. Thats why we need two calls to g_rand_int */ @@ -565,17 +581,19 @@ g_rand_double (GRand* rand) /** * g_rand_double_range: - * @rand_: a #GRand. - * @begin: lower closed bound of the interval. - * @end: upper open bound of the interval. + * @rand_: a #GRand + * @begin: lower closed bound of the interval + * @end: upper open bound of the interval * * Returns the next random #gdouble from @rand_ equally distributed over * the range [@begin..@end). * - * Return value: A random number. - **/ + * Returns: a random number + */ gdouble -g_rand_double_range (GRand* rand, gdouble begin, gdouble end) +g_rand_double_range (GRand *rand, + gdouble begin, + gdouble end) { gdouble r; @@ -584,52 +602,61 @@ g_rand_double_range (GRand* rand, gdouble begin, gdouble end) return r * end - (r - 1) * begin; } +static GRand * +get_global_random (void) +{ + static GRand *global_random; + + /* called while locked */ + if (!global_random) + global_random = g_rand_new (); + + return global_random; +} + /** * g_random_boolean: - * @Returns: a random #gboolean. * - * Returns a random #gboolean. This corresponds to a unbiased coin toss. - **/ + * Returns a random #gboolean. + * This corresponds to a unbiased coin toss. + * + * Returns: a random #gboolean + */ /** * g_random_int: * * Return a random #guint32 equally distributed over the range * [0..2^32-1]. * - * Return value: A random number. - **/ + * Returns: a random number + */ 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); + result = g_rand_int (get_global_random ()); G_UNLOCK (global_random); return result; } /** * g_random_int_range: - * @begin: lower closed bound of the interval. - * @end: upper open bound of the interval. + * @begin: lower closed bound of the interval + * @end: upper open bound of the interval * * Returns a random #gint32 equally distributed over the range * [@begin..@end-1]. * - * Return value: A random number. - **/ + * Returns: a random number + */ gint32 -g_random_int_range (gint32 begin, gint32 end) +g_random_int_range (gint32 begin, + gint32 end) { gint32 result; G_LOCK (global_random); - if (!global_random) - global_random = g_rand_new (); - - result = g_rand_int_range (global_random, begin, end); + result = g_rand_int_range (get_global_random (), begin, end); G_UNLOCK (global_random); return result; } @@ -639,57 +666,50 @@ g_random_int_range (gint32 begin, gint32 end) * * Returns a random #gdouble equally distributed over the range [0..1). * - * Return value: A random number. - **/ + * Returns: a random number + */ 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); + result = g_rand_double (get_global_random ()); G_UNLOCK (global_random); return result; } /** * g_random_double_range: - * @begin: lower closed bound of the interval. - * @end: upper open bound of the interval. + * @begin: lower closed bound of the interval + * @end: upper open bound of the interval * - * Returns a random #gdouble equally distributed over the range [@begin..@end). + * Returns a random #gdouble equally distributed over the range + * [@begin..@end). * - * Return value: A random number. - **/ + * Returns: a random number + */ gdouble -g_random_double_range (gdouble begin, gdouble end) +g_random_double_range (gdouble begin, + gdouble end) { double result; G_LOCK (global_random); - if (!global_random) - global_random = g_rand_new (); - - result = g_rand_double_range (global_random, begin, end); + result = g_rand_double_range (get_global_random (), begin, end); G_UNLOCK (global_random); return result; } /** * g_random_set_seed: - * @seed: a value to reinitialize the global random number generator. + * @seed: a value to reinitialize the global random number generator * * Sets the seed for the global random number generator, which is used - * by the g_random_* functions, to @seed. - **/ + * by the g_random_* functions, to @seed. + */ 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_rand_set_seed (get_global_random (), seed); G_UNLOCK (global_random); }