From ffcf100c002e7d343cb068e68522791e3651d773 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Fri, 30 Apr 2010 18:36:51 +0200 Subject: [PATCH] Replace rng_rand_range() with GLib's g_rand_int_range() that works better --- src/rng.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/rng.c b/src/rng.c index b53e05bf..5b57e06a 100644 --- a/src/rng.c +++ b/src/rng.c @@ -88,22 +88,40 @@ rng_rand(struct rng_ctx *ctx) return ctx->iy; } -/* Integer in [min, max[, min >= 0 */ +/* Integer in [min, max[ */ +/* Taken from GLib 2.0 v2.25.3, g_rand_int_range(), GPLv2+ */ int32_t rng_rand_range(struct rng_ctx *ctx, int32_t min, int32_t max) { int32_t res; - int32_t range; + int32_t dist; + uint32_t maxvalue; + uint32_t leftover; - range = max - min; + dist = max - min; - res = rng_rand(ctx); - res = (int32_t)((double)range * ((1.0 / 2147483647.0) * (double)res)); + if (dist <= 0) + return min; - if (min > 0) - res += min; + /* maxvalue is set to the predecessor of the greatest + * multiple of dist less or equal 2^32. */ + if (dist <= 0x80000000u) /* 2^31 */ + { + /* maxvalue = 2^32 - 1 - (2^32 % dist) */ + leftover = (0x80000000u % dist) * 2; + if (leftover >= dist) + leftover -= dist; + maxvalue = 0xffffffffu - leftover; + } + else + maxvalue = dist - 1; + do + res = rng_rand(ctx); + while (res > maxvalue); - return res; + res %= dist; + + return min + res; } /* Fisher-Yates shuffling algorithm