Updated G_RAND_DOUBLE_TRANSFORM to be more accurate. Redid g_rand_double()
authorSebastian Wilhelmi <wilhelmi@ira.uka.de>
Tue, 19 Dec 2000 15:57:53 +0000 (15:57 +0000)
committerSebastian Wilhelmi <wilhelmi@src.gnome.org>
Tue, 19 Dec 2000 15:57:53 +0000 (15:57 +0000)
2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>

* grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
accurate. Redid g_rand_double() such that it returns 52 bits after
the point instead of 32 as before. That OTOH requires calling
g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
now thanks to the new precision of g_rand_double(). Thanks to
Sverre Johansen <sj@ifi.uio.no> for the hint.

* grand.h: Added g_rand_boolean() and g_random_boolean()
macros. While they could be omitted due to extreme simplicity,
they make intention clearer in code and are therefore good to have.

* grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
begin' and 'end' resp. to avoid making people think, that 'max' is
included in the interval. 'end' now isn't, whereas 'begin'
is. That's similar to the use in the STL.

* glib/glib-sections.txt: Added g_rand_boolean and
g_random_boolean macros.

* glib/tmpl/random_numbers.sgml: Updated.

15 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/ChangeLog
docs/reference/glib/glib-sections.txt
docs/reference/glib/tmpl/random_numbers.sgml
glib/grand.c
glib/grand.h
grand.c
grand.h

index 85e5cc0..05e2205 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 85e5cc0..05e2205 100644 (file)
@@ -1,5 +1,21 @@
 2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
+       * grand.c: Updated G_RAND_DOUBLE_TRANSFORM to be more
+       accurate. Redid g_rand_double() such that it returns 52 bits after
+       the point instead of 32 as before. That OTOH requires calling
+       g_rand_int() twice. Overhauled g_rand_int_range(), which is easier
+       now thanks to the new precision of g_rand_double(). Thanks to
+       Sverre Johansen <sj@ifi.uio.no> for the hint.
+
+       * grand.h: Added g_rand_boolean() and g_random_boolean()
+       macros. While they could be omitted due to extreme simplicity,
+       they make intention clearer in code and are therefore good to have.
+
+       * grand.c, grand.h: Renamed all 'min' and 'max' parameters to'
+       begin' and 'end' resp. to avoid making people think, that 'max' is
+       included in the interval. 'end' now isn't, whereas 'begin'
+       is. That's similar to the use in the STL.
+
        * gslist.c, glist.c: Ok, I'm a moron. When I originally
        implemented ENABLE_GC_FRIENDLY, I forgot to include config.h into
        the affected files. Now that Alex did that for those two,
index 9f02516..c24794f 100644 (file)
@@ -1,3 +1,10 @@
+2000-12-19  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * glib/glib-sections.txt: Added g_rand_boolean and
+       g_random_boolean macros.
+
+       * glib/tmpl/random_numbers.sgml: Updated.
+       
 Tue Dec  5 15:41:23 2000  Owen Taylor  <otaylor@redhat.com>
 
         * glib/Makefile.am glib/mainloop-states*: add images
index 2c2a17a..034086c 100644 (file)
@@ -1626,11 +1626,13 @@ g_rand_new_with_seed
 g_rand_new
 g_rand_free
 g_rand_set_seed
+g_rand_boolean
 g_rand_int
 g_rand_int_range
 g_rand_double
 g_rand_double_range
 g_random_set_seed
+g_random_boolean
 g_random_int
 g_random_int_range
 g_random_double
index c2b34c5..4282c52 100644 (file)
@@ -32,14 +32,6 @@ distributed random numbers, whereas for example the
 yield equally distributed numbers.
 </para>
 
-<para>
-A random binary decision is best implemented by using
-<literal>if(g_random_int()&amp;(1<<@a))</literal>, where @a can be every
-integer constant from 0 to 31. The Mersenne Twister PRNG is said to
-produce highly random lower bits too, but it is common not to rely on
-that, so choosing @a to be from 4 to 31 might be wise.
-</para>
-
 <!-- ##### SECTION See_Also ##### -->
 <para>
 
@@ -78,6 +70,16 @@ accessed through the g_rand_* functions.
 @seed: 
 
 
+<!-- ##### MACRO g_rand_boolean ##### -->
+<para>
+Return a random #gboolean from @rand. This corresponds to a unbiased
+coin toss.
+</para>
+
+@rand: a #GRand.
+@Returns: a random #gboolean.
+
+
 <!-- ##### FUNCTION g_rand_int ##### -->
 
 
@@ -89,8 +91,8 @@ accessed through the g_rand_* functions.
 
 
 @rand: 
-@min: 
-@max
+@begin: 
+@end
 @Returns: 
 
 
@@ -105,8 +107,8 @@ accessed through the g_rand_* functions.
 
 
 @rand: 
-@min: 
-@max
+@begin: 
+@end
 @Returns: 
 
 
@@ -116,6 +118,14 @@ accessed through the g_rand_* functions.
 @seed: 
 
 
+<!-- ##### MACRO g_random_boolean ##### -->
+<para>
+Return a random #gboolean. This corresponds to a unbiased coin toss.
+</para>
+
+@Returns: a random #gboolean.
+
+
 <!-- ##### FUNCTION g_random_int ##### -->
 
 
@@ -125,8 +135,8 @@ accessed through the g_rand_* functions.
 <!-- ##### FUNCTION g_random_int_range ##### -->
 
 
-@min: 
-@max
+@begin: 
+@end
 @Returns: 
 
 
@@ -139,8 +149,8 @@ accessed through the g_rand_* functions.
 <!-- ##### FUNCTION g_random_double_range ##### -->
 
 
-@min: 
-@max
+@begin: 
+@end
 @Returns: 
 
 
index b62257e..2a60e5b 100644 (file)
@@ -200,71 +200,61 @@ g_rand_int (GRand* rand)
   return y; 
 }
 
+/* transform [0..2^32] -> [0..1] */
+#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10
+
 /**
  * g_rand_int_range:
  * @rand: a #GRand.
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
  * Return the next random #gint32 from @rand equaly distributed over
- * the range [@min..@max-1].
+ * the range [@begin..@end-1].
  *
  * Return value: A random number.
  **/
 gint32 
-g_rand_int_range (GRand* rand, gint32 min, gint32 max)
+g_rand_int_range (GRand* rand, gint32 begin, gint32 end)
 {
-  guint32 dist = max - min;
+  guint32 dist = end - begin;
   guint32 random;
 
-  g_return_val_if_fail (rand != NULL, min);
-  g_return_val_if_fail (max > min, min);
+  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 */
     {
-      /* 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 */
+      /* 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) 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));  */
+      random = (gint32) (double_rand * 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);
+      /* 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);
     }
-  return min + random;
+  return begin + random;
 }
 
-/* transform [0..2^32-1] -> [0..1) */
-#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386963e-10
-
 /**
  * g_rand_double:
  * @rand: a #GRand.
@@ -276,25 +266,35 @@ g_rand_int_range (GRand* rand, gint32 min, gint32 max)
  **/
 gdouble 
 g_rand_double (GRand* rand)
-{                            
-  return g_rand_int (rand) * G_RAND_DOUBLE_TRANSFORM;
+{    
+  /* 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 */
+  gdouble retval = g_rand_int (rand) * G_RAND_DOUBLE_TRANSFORM;
+  retval = (retval + g_rand_int (rand)) * G_RAND_DOUBLE_TRANSFORM;
+
+  /* The following might happen due to very bad rounding luck, but
+   * actually this should be more than rare, we just try again then */
+  if (retval >= 1.0) 
+    return g_rand_double (rand);
+
+  return retval;
 }
 
 /**
  * g_rand_double_range:
  * @rand: a #GRand.
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
  * Return the next random #gdouble from @rand equaly distributed over
- * the range [@min..@max).
+ * the range [@begin..@end).
  *
  * Return value: A random number.
  **/
 gdouble 
-g_rand_double_range (GRand* rand, gdouble min, gdouble max)
+g_rand_double_range (GRand* rand, gdouble begin, gdouble end)
 {
-  return g_rand_int (rand) * ((max - min) * G_RAND_DOUBLE_TRANSFORM)  + min;
+  return g_rand_double (rand) * (end - begin) + begin;
 }
 
 /**
@@ -320,23 +320,23 @@ g_random_int (void)
 
 /**
  * g_random_int_range:
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
  * Return a random #gint32 equaly distributed over the range
- * [@min..@max-1].
+ * [@begin..@end-1].
  *
  * Return value: A random number.
  **/
 gint32 
-g_random_int_range (gint32 min, gint32 max)
+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, min, max);
+  result = g_rand_int_range (global_random, begin, end);
   G_UNLOCK (global_random);
   return result;
 }
@@ -363,22 +363,22 @@ g_random_double (void)
 
 /**
  * g_random_double_range:
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
- * Return a random #gdouble equaly distributed over the range [@min..@max).
+ * Return a random #gdouble equaly distributed over the range [@begin..@end).
  *
  * Return value: A random number.
  **/
 gdouble 
-g_random_double_range (gdouble min, gdouble max)
+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, min, max);
+  result = g_rand_double_range (global_random, begin, end);
   G_UNLOCK (global_random);
   return result;
 }
index 38f4e5e..8cbeff6 100644 (file)
@@ -35,11 +35,11 @@ typedef struct _GRand           GRand;
 
 /* 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).
+ * The range functions return a value in the intervall [begin, end).
  * int          -> [0..2^32-1]
- * int_range    -> [min..max-1]
+ * int_range    -> [begin..end-1]
  * double       -> [0..1)
- * double_range -> [min..max)
+ * double_range -> [begin..end)
  */
 
 GRand*  g_rand_new_with_seed   (guint32     seed);
@@ -48,22 +48,28 @@ void    g_rand_free            (GRand      *rand);
 
 void    g_rand_set_seed        (GRand      *rand,
                                 guint32     seed);
+
+#define g_rand_boolean(rand) (g_rand_int ((rand)) & (1<<15))
+
 guint32 g_rand_int             (GRand      *rand);
 gint32  g_rand_int_range       (GRand      *rand,
-                                gint32      min,
-                                gint32      max);
+                                gint32      begin,
+                                gint32      end);
 gdouble g_rand_double          (GRand      *rand);
 gdouble g_rand_double_range    (GRand      *rand,
-                                gdouble     min,
-                                gdouble     max);
+                                gdouble     begin,
+                                gdouble     end);
 
 void    g_random_set_seed      (guint32     seed);
+
+#define g_random_boolean() (g_rand_boolean ((rand)))
+
 guint32 g_random_int           (void);
-gint32  g_random_int_range     (gint32      min,
-                                gint32      max);
+gint32  g_random_int_range     (gint32      begin,
+                                gint32      end);
 gdouble g_random_double        (void);
-gdouble g_random_double_range  (gdouble     min,
-                                gdouble     max);
+gdouble g_random_double_range  (gdouble     begin,
+                                gdouble     end);
 
 G_END_DECLS
 
diff --git a/grand.c b/grand.c
index b62257e..2a60e5b 100644 (file)
--- a/grand.c
+++ b/grand.c
@@ -200,71 +200,61 @@ g_rand_int (GRand* rand)
   return y; 
 }
 
+/* transform [0..2^32] -> [0..1] */
+#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10
+
 /**
  * g_rand_int_range:
  * @rand: a #GRand.
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
  * Return the next random #gint32 from @rand equaly distributed over
- * the range [@min..@max-1].
+ * the range [@begin..@end-1].
  *
  * Return value: A random number.
  **/
 gint32 
-g_rand_int_range (GRand* rand, gint32 min, gint32 max)
+g_rand_int_range (GRand* rand, gint32 begin, gint32 end)
 {
-  guint32 dist = max - min;
+  guint32 dist = end - begin;
   guint32 random;
 
-  g_return_val_if_fail (rand != NULL, min);
-  g_return_val_if_fail (max > min, min);
+  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 */
     {
-      /* 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 */
+      /* 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) 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));  */
+      random = (gint32) (double_rand * 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);
+      /* 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);
     }
-  return min + random;
+  return begin + random;
 }
 
-/* transform [0..2^32-1] -> [0..1) */
-#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386963e-10
-
 /**
  * g_rand_double:
  * @rand: a #GRand.
@@ -276,25 +266,35 @@ g_rand_int_range (GRand* rand, gint32 min, gint32 max)
  **/
 gdouble 
 g_rand_double (GRand* rand)
-{                            
-  return g_rand_int (rand) * G_RAND_DOUBLE_TRANSFORM;
+{    
+  /* 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 */
+  gdouble retval = g_rand_int (rand) * G_RAND_DOUBLE_TRANSFORM;
+  retval = (retval + g_rand_int (rand)) * G_RAND_DOUBLE_TRANSFORM;
+
+  /* The following might happen due to very bad rounding luck, but
+   * actually this should be more than rare, we just try again then */
+  if (retval >= 1.0) 
+    return g_rand_double (rand);
+
+  return retval;
 }
 
 /**
  * g_rand_double_range:
  * @rand: a #GRand.
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
  * Return the next random #gdouble from @rand equaly distributed over
- * the range [@min..@max).
+ * the range [@begin..@end).
  *
  * Return value: A random number.
  **/
 gdouble 
-g_rand_double_range (GRand* rand, gdouble min, gdouble max)
+g_rand_double_range (GRand* rand, gdouble begin, gdouble end)
 {
-  return g_rand_int (rand) * ((max - min) * G_RAND_DOUBLE_TRANSFORM)  + min;
+  return g_rand_double (rand) * (end - begin) + begin;
 }
 
 /**
@@ -320,23 +320,23 @@ g_random_int (void)
 
 /**
  * g_random_int_range:
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
  * Return a random #gint32 equaly distributed over the range
- * [@min..@max-1].
+ * [@begin..@end-1].
  *
  * Return value: A random number.
  **/
 gint32 
-g_random_int_range (gint32 min, gint32 max)
+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, min, max);
+  result = g_rand_int_range (global_random, begin, end);
   G_UNLOCK (global_random);
   return result;
 }
@@ -363,22 +363,22 @@ g_random_double (void)
 
 /**
  * g_random_double_range:
- * @min: lower closed bound of the interval.
- * @max: upper open bound of the interval.
+ * @begin: lower closed bound of the interval.
+ * @end: upper open bound of the interval.
  *
- * Return a random #gdouble equaly distributed over the range [@min..@max).
+ * Return a random #gdouble equaly distributed over the range [@begin..@end).
  *
  * Return value: A random number.
  **/
 gdouble 
-g_random_double_range (gdouble min, gdouble max)
+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, min, max);
+  result = g_rand_double_range (global_random, begin, end);
   G_UNLOCK (global_random);
   return result;
 }
diff --git a/grand.h b/grand.h
index 38f4e5e..8cbeff6 100644 (file)
--- a/grand.h
+++ b/grand.h
@@ -35,11 +35,11 @@ typedef struct _GRand           GRand;
 
 /* 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).
+ * The range functions return a value in the intervall [begin, end).
  * int          -> [0..2^32-1]
- * int_range    -> [min..max-1]
+ * int_range    -> [begin..end-1]
  * double       -> [0..1)
- * double_range -> [min..max)
+ * double_range -> [begin..end)
  */
 
 GRand*  g_rand_new_with_seed   (guint32     seed);
@@ -48,22 +48,28 @@ void    g_rand_free            (GRand      *rand);
 
 void    g_rand_set_seed        (GRand      *rand,
                                 guint32     seed);
+
+#define g_rand_boolean(rand) (g_rand_int ((rand)) & (1<<15))
+
 guint32 g_rand_int             (GRand      *rand);
 gint32  g_rand_int_range       (GRand      *rand,
-                                gint32      min,
-                                gint32      max);
+                                gint32      begin,
+                                gint32      end);
 gdouble g_rand_double          (GRand      *rand);
 gdouble g_rand_double_range    (GRand      *rand,
-                                gdouble     min,
-                                gdouble     max);
+                                gdouble     begin,
+                                gdouble     end);
 
 void    g_random_set_seed      (guint32     seed);
+
+#define g_random_boolean() (g_rand_boolean ((rand)))
+
 guint32 g_random_int           (void);
-gint32  g_random_int_range     (gint32      min,
-                                gint32      max);
+gint32  g_random_int_range     (gint32      begin,
+                                gint32      end);
 gdouble g_random_double        (void);
-gdouble g_random_double_range  (gdouble     min,
-                                gdouble     max);
+gdouble g_random_double_range  (gdouble     begin,
+                                gdouble     end);
 
 G_END_DECLS