Make the expression code a little nicer and fix bugs found
[pspp] / src / random.c
index d62c1a3dede81e2a64e789c1cebedc604c25871f..e6db94c1501f06f606d8fc1af86c4897dcc8d43f 100644 (file)
@@ -18,7 +18,8 @@
    02111-1307, USA. */
 
 #include <config.h>
-#include <assert.h>
+#include "random.h"
+#include "error.h"
 #include <inttypes.h>
 #include <limits.h>
 #include <math.h>
@@ -26,7 +27,6 @@
 #include <time.h>
 #include "alloc.h"
 #include "magic.h"
-#include "random.h"
 #include "settings.h"
 
 /* Random number generator. */
@@ -40,23 +40,55 @@ struct rng
     double next_normal;
   };
 
+
+/* Return a `random' seed by using the real time clock */
+unsigned long
+random_seed(void)
+{
+  time_t t;
+  
+  time(&t);
+
+  return (unsigned long) t;
+}
+
 /* Creates a new random number generator, seeds it based on
    the current time, and returns it. */
 struct rng *
 rng_create (void) 
 {
   struct rng *rng;
-  static time_t t;
-
-   rng = xmalloc (sizeof *rng);
-   if (t == 0)
-     time (&t);
-   else
-     t++;
-   rng_seed (rng, &t, sizeof t);
-   rng->next_normal = NOT_DOUBLE;
-   return rng;
- }
+  static unsigned long seed=0;
+  unsigned long s;
+
+  rng = xmalloc (sizeof *rng);
+
+
+  if ( seed_is_set(&s) ) 
+    {
+      seed = s;
+    }
+  else if ( seed == 0 ) 
+    {
+      seed = random_seed();
+    }
+  assert(seed);
+  /* 
+  if (t == 0 || set_seed_used)
+  {
+    if (set_seed == NOT_LONG) 
+      time (&t);
+    else
+      t = set_seed;
+    set_seed_used=0;
+  }
+  else
+    t++;
+  */
+  rng_seed (rng, &seed, sizeof seed);
+  rng->next_normal = NOT_DOUBLE;
+  return rng;
+}
 
 /* Destroys RNG. */
 void
@@ -66,7 +98,7 @@ rng_destroy (struct rng *rng)
 }
 
 /* Swap bytes. */
-static inline void
+static void
 swap_byte (uint8_t *a, uint8_t *b) 
 {
   uint8_t t = *a;
@@ -80,7 +112,7 @@ void
 rng_seed (struct rng *rng, const void *key_, size_t size) 
 {
   const uint8_t *key = key_;
-  int key_idx;
+  size_t key_idx;
   uint8_t *s;
   int i, j;
 
@@ -90,7 +122,7 @@ rng_seed (struct rng *rng, const void *key_, size_t size)
   rng->i = rng->j = 0;
   for (i = 0; i < 256; i++) 
     s[i] = i;
-  for (key_idx = 0, i = 0; i < 256; i++) 
+  for (key_idx = 0, i = j = 0; i < 256; i++) 
     {
       j = (j + s[i] + key[key_idx]) & 255;
       swap_byte (s + i, s + j);
@@ -154,10 +186,16 @@ rng_get_unsigned (struct rng *rng)
 double
 rng_get_double (struct rng *rng) 
 {
-  unsigned long value;
-
-  rng_get_bytes (rng, &value, sizeof value);
-  return value / ULONG_MAX;
+  for (;;) 
+    {
+      unsigned long ulng;
+      double dbl;
+  
+      rng_get_bytes (rng, &ulng, sizeof ulng);
+      dbl = ulng / (ULONG_MAX + 1.0);
+      if (dbl >= 0 && dbl < 1)
+        return dbl;
+    }
 }
 
 /* Returns a random number from the distribution with mean 0 and