diff --git a/docs/reference/glib/tmpl/random_numbers.sgml b/docs/reference/glib/tmpl/random_numbers.sgml index 9ff4ee544..197501845 100644 --- a/docs/reference/glib/tmpl/random_numbers.sgml +++ b/docs/reference/glib/tmpl/random_numbers.sgml @@ -36,12 +36,18 @@ 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. The original seeding -algorithm, as found in GLib 2.0.x, can be used instead of the new one -by setting the environment variable G_RANDOM_VERSION to -the value of '2.0'. Use the GLib-2.0 algorithm only if you have -sequences of numbers generated with Glib-2.0 that you need to -reproduce exactly. +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. diff --git a/glib/grand.c b/glib/grand.c index f328878d5..1ec78d5db 100644 --- a/glib/grand.c +++ b/glib/grand.c @@ -285,34 +285,62 @@ g_rand_int_range (GRand* rand, gint32 begin, gint32 end) g_return_val_if_fail (rand != NULL, begin); g_return_val_if_fail (end > begin, begin); - /* All tricks doing modulo calculations do not have a perfect - * distribution -> We must use the slower way through gdouble for - * maximal quality. */ - - if (dist <= 0x10000L) /* 2^16 */ + switch (get_random_version ()) { - /* 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 - * 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. - */ - - gdouble double_rand = g_rand_int (rand) * - (G_RAND_DOUBLE_TRANSFORM + - G_RAND_DOUBLE_TRANSFORM * G_RAND_DOUBLE_TRANSFORM); - - random = (gint32) (double_rand * dist); - } - 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 */ - random = (gint32) g_rand_double_range (rand, 0, dist); - } + case 20: + if (dist <= 0x10000L) /* 2^16 */ + { + /* 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 + * 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. + */ + + gdouble double_rand = g_rand_int (rand) * + (G_RAND_DOUBLE_TRANSFORM + + G_RAND_DOUBLE_TRANSFORM * G_RAND_DOUBLE_TRANSFORM); + + random = (gint32) (double_rand * dist); + } + 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 */ + random = (gint32) g_rand_double_range (rand, 0, dist); + } + break; + case 22: + if (dist == 0) + random = 0; + else + { + /* maxvalue is set to the predecessor of the greatest + * multiple of dist less or equal 2^32. */ + guint32 maxvalue; + if (dist <= 0x80000000u) /* 2^31 */ + { + /* maxvalue = 2^32 - 1 - (2^32 % dist) */ + guint32 leftover = (0x80000000u % dist) * 2; + if (leftover >= dist) leftover -= dist; + maxvalue = 0xffffffffu - leftover; + } + else + maxvalue = dist - 1; + + do + random = g_rand_int (rand); + while (random > maxvalue); + + random %= dist; + } + break; + default: + g_assert_not_reached (); + } return begin + random; }