added some more random generator functions (from glib)
[rocksndiamonds.git] / src / game_bd / bd_random.c
index 085308632dca06997cfe8246326934057dd4ac68..fc7998cbdb936718bac7321286d647c7e1722bfa 100644 (file)
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <time.h>
 
 #if defined(PLATFORM_WINDOWS)
-#include <process.h>   /* for getpid() */
+#include <process.h>   // for getpid()
 #endif
 
 #include "main_bd.h"
  * accessed through the gd_rand_* functions.
  **/
 
-/* Period parameters */
+// Period parameters
 #define N 624
 #define M 397
-#define MATRIX_A   0x9908b0df /* constant vector a */
-#define UPPER_MASK 0x80000000 /* most significant w-r bits */
-#define LOWER_MASK 0x7fffffff /* least significant r bits */
+#define MATRIX_A   0x9908b0df // constant vector a
+#define UPPER_MASK 0x80000000 // most significant w-r bits
+#define LOWER_MASK 0x7fffffff // least significant r bits
 
-/* Tempering parameters */
+// Tempering parameters
 #define TEMPERING_MASK_B 0x9d2c5680
 #define TEMPERING_MASK_C 0xefc60000
 #define TEMPERING_SHIFT_U(y)  (y >> 11)
@@ -70,7 +71,7 @@
 
 struct _GdRand
 {
-  unsigned int mt[N]; /* the array for the state vector  */
+  unsigned int mt[N]; // the array for the state vector
   unsigned int mti;
 };
 
@@ -175,7 +176,7 @@ gd_rand_new (void)
     seed[2] = getpid ();
     seed[3] = getppid ();
   }
-#else /* PLATFORM_WINDOWS */
+#else // PLATFORM_WINDOWS
   /* rand_s() is only available since Visual Studio 2005 and
    * MinGW-w64 has a wrapper that will emulate rand_s() if it's not in msvcrt
    */
@@ -253,9 +254,9 @@ gd_rand_set_seed (GdRand *rand, unsigned int seed)
   if (rand == NULL)
     return;
 
-  /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
-  /* In the previous version (see above), MSBs of the    */
-  /* seed affect only MSBs of the array mt[].            */
+  // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
+  // In the previous version (see above), MSBs of the
+  // seed affect only MSBs of the array mt[].
 
   rand->mt[0] = seed;
   for (rand->mti = 1; rand->mti < N; rand->mti++)
@@ -294,8 +295,8 @@ gd_rand_set_seed_array (GdRand *rand, const unsigned int *seed, unsigned int see
   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 */
+                  + seed[j] + j);      // non linear
+    rand->mt[i] &= 0xffffffffUL;       // for WORDSIZE > 32 machines
     i++;
     j++;
 
@@ -312,8 +313,8 @@ gd_rand_set_seed_array (GdRand *rand, const unsigned int *seed, unsigned int see
   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);                // non linear
+    rand->mt[i] &= 0xffffffffUL;       // for WORDSIZE > 32 machines
     i++;
 
     if (i >= N)
@@ -323,7 +324,7 @@ gd_rand_set_seed_array (GdRand *rand, const unsigned int *seed, unsigned int see
     }
   }
 
-  rand->mt[0] = 0x80000000UL;          /* MSB is 1; assuring non-zero initial array */
+  rand->mt[0] = 0x80000000UL;          // MSB is 1; assuring non-zero initial array
 }
 
 /**
@@ -349,14 +350,14 @@ gd_rand_int (GdRand *rand)
 {
   unsigned int y;
   static const unsigned int mag01[2] = { 0x0, MATRIX_A };
-  /* mag01[x] = x * MATRIX_A  for x=0,1 */
+  // mag01[x] = x * MATRIX_A  for x=0,1
 
   if (rand == NULL)
     return 0;
 
   if (rand->mti >= N)
   {
-    /* generate N words at one time */
+    // generate N words at one time
     int kk;
 
     for (kk = 0; kk < N - M; kk++)
@@ -386,6 +387,9 @@ gd_rand_int (GdRand *rand)
   return y;
 }
 
+// transform [0..2^32] -> [0..1]
+#define GD_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10
+
 /**
  * gd_rand_int_range:
  * @rand_: a #GdRand
@@ -413,9 +417,9 @@ gd_rand_int_range (GdRand *rand, int begin, int end)
    * multiple of dist less or equal 2^32.
    */
   unsigned int maxvalue;
-  if (dist <= 0x80000000u) /* 2^31 */
+  if (dist <= 0x80000000u) // 2^31
   {
-    /* maxvalue = 2^32 - 1 - (2^32 % dist) */
+    // maxvalue = 2^32 - 1 - (2^32 % dist)
     unsigned int leftover = (0x80000000u % dist) * 2;
     if (leftover >= dist) leftover -= dist;
     maxvalue = 0xffffffffu - leftover;
@@ -434,18 +438,90 @@ gd_rand_int_range (GdRand *rand, int begin, int end)
   return begin + random;
 }
 
+/**
+ * gd_rand_double:
+ * @rand_: a #GRand
+ *
+ * Returns the next random #double from @rand_ equally distributed over
+ * the range [0..1).
+ *
+ * Returns: a random number
+ */
+double
+gd_rand_double (GdRand *rand)
+{
+  /* We set all 52 bits after the point for this, not only the first
+     32. That's why we need two calls to gd_rand_int */
+  double retval = gd_rand_int(rand) * GD_RAND_DOUBLE_TRANSFORM;
+  retval = (retval + gd_rand_int(rand)) * GD_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 gd_rand_double (rand);
+
+  return retval;
+}
+
+/**
+ * gd_rand_double_range:
+ * @rand_: a #GRand
+ * @begin: lower closed bound of the interval
+ * @end: upper open bound of the interval
+ *
+ * Returns the next random #double from @rand_ equally distributed over
+ * the range [@begin..@end).
+ *
+ * Returns: a random number
+ */
+double
+gd_rand_double_range (GdRand *rand, double begin, double end)
+{
+  double r;
+
+  r = gd_rand_double(rand);
+
+  return r * end - (r - 1) * begin;
+}
+
 static GdRand *
 get_global_random (void)
 {
   static GdRand *global_random;
 
-  /* called while locked */
+  // called while locked
   if (!global_random)
     global_random = gd_rand_new();
 
   return global_random;
 }
 
+/**
+ * gd_random_boolean:
+ *
+ * Returns a random #gboolean.
+ * This corresponds to an unbiased coin toss.
+ *
+ * Returns: a random #gboolean
+ */
+/**
+ * gd_random_int:
+ *
+ * Return a random #guint32 equally distributed over the range
+ * [0..2^32-1].
+ *
+ * Returns: a random number
+ */
+unsigned int
+gd_random_int (void)
+{
+  unsigned int result;
+
+  result = gd_rand_int(get_global_random());
+
+  return result;
+}
+
 /**
  * gd_random_int_range:
  * @begin: lower closed bound of the interval
@@ -465,3 +541,40 @@ gd_random_int_range (int begin, int end)
 
   return result;
 }
+
+/**
+ * gd_random_double:
+ *
+ * Returns a random #double equally distributed over the range [0..1).
+ *
+ * Returns: a random number
+ */
+double
+gd_random_double (void)
+{
+  double result;
+
+  result = gd_rand_double(get_global_random());
+
+  return result;
+}
+
+/**
+ * gd_random_double_range:
+ * @begin: lower closed bound of the interval
+ * @end: upper open bound of the interval
+ *
+ * Returns a random #double equally distributed over the range
+ * [@begin..@end).
+ *
+ * Returns: a random number
+ */
+double
+gd_random_double_range (double begin, double end)
+{
+  double result;
+
+  result = gd_rand_double_range(get_global_random(), begin, end);
+
+  return result;
+}