Merge branch 'master' into boehm-demers-weiser-gc
[bpt/guile.git] / libguile / random.c
index 991900a..f5f706f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999,2000,2001, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999,2000,2001, 2003, 2005, 2006 Free Software Foundation, Inc.
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 
 
 /* Author: Mikael Djurfeldt <djurfeldt@nada.kth.se> */
 
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
 
@@ -33,6 +33,7 @@
 #include "libguile/feature.h"
 #include "libguile/strings.h"
 #include "libguile/unif.h"
+#include "libguile/srfi-4.h"
 #include "libguile/vectors.h"
 
 #include "libguile/validate.h"
@@ -74,13 +75,13 @@ scm_t_rng scm_the_rng;
 #define M_PI 3.14159265359
 #endif
 
-#ifdef SCM_HAVE_T_INT64
+#if SCM_HAVE_T_UINT64
 
 unsigned long
 scm_i_uniform32 (scm_t_i_rstate *state)
 {
-  scm_t_int64 x = (scm_t_int64) A * state->w + state->c;
-  scm_t_int32 w = x & 0xffffffffUL;
+  scm_t_uint64 x = (scm_t_uint64) A * state->w + state->c;
+  scm_t_uint32 w = x & 0xffffffffUL;
   state->w = w;
   state->c = x >> 32L;
   return w;
@@ -105,12 +106,12 @@ scm_i_uniform32 (scm_t_i_rstate *state)
 unsigned long
 scm_i_uniform32 (scm_t_i_rstate *state)
 {
-  scm_t_int32 x1 = L (A) * L (state->w);
-  scm_t_int32 x2 = L (A) * H (state->w);
-  scm_t_int32 x3 = H (A) * L (state->w);
-  scm_t_int32 w = L (x1) + L (state->c);
-  scm_t_int32 m = H (x1) + L (x2) + L (x3) + H (state->c) + H (w);
-  scm_t_int32 x4 = H (A) * H (state->w);
+  scm_t_uint32 x1 = L (A) * L (state->w);
+  scm_t_uint32 x2 = L (A) * H (state->w);
+  scm_t_uint32 x3 = H (A) * L (state->w);
+  scm_t_uint32 w = L (x1) + L (state->c);
+  scm_t_uint32 m = H (x1) + L (x2) + L (x3) + H (state->c) + H (w);
+  scm_t_uint32 x4 = H (A) * H (state->w);
   state->w = w = (L (m) << 16) + L (w);
   state->c = H (x2) + H (x3) + x4 + H (m);
   return w;
@@ -119,10 +120,10 @@ scm_i_uniform32 (scm_t_i_rstate *state)
 #endif
 
 void
-scm_i_init_rstate (scm_t_i_rstate *state, char *seed, int n)
+scm_i_init_rstate (scm_t_i_rstate *state, const char *seed, int n)
 {
-  scm_t_int32 w = 0L;
-  scm_t_int32 c = 0L;
+  scm_t_uint32 w = 0L;
+  scm_t_uint32 c = 0L;
   int i, m;
   for (i = 0; i < n; ++i)
     {
@@ -132,7 +133,7 @@ scm_i_init_rstate (scm_t_i_rstate *state, char *seed, int n)
       else
         c += seed[i] << (8 * (m - 4));
     }
-  if ((w == 0 && c == 0) || (w == 0xffffffffUL && c == A - 1))
+  if ((w == 0 && c == 0) || (w == -1 && c == A - 1))
     ++c;
   state->w = w;
   state->c = c;
@@ -141,9 +142,10 @@ scm_i_init_rstate (scm_t_i_rstate *state, char *seed, int n)
 scm_t_i_rstate *
 scm_i_copy_rstate (scm_t_i_rstate *state)
 {
-  scm_t_rstate *new_state = scm_malloc (scm_the_rng.rstate_size);
-  if (new_state == 0)
-    scm_memory_error ("rstate");
+  scm_t_rstate *new_state;
+
+  new_state = scm_gc_malloc_pointerless (scm_the_rng.rstate_size,
+                                        "random-state");
   return memcpy (new_state, state, scm_the_rng.rstate_size);
 }
 
@@ -153,11 +155,12 @@ scm_i_copy_rstate (scm_t_i_rstate *state)
  */
 
 scm_t_rstate *
-scm_c_make_rstate (char *seed, int n)
+scm_c_make_rstate (const char *seed, int n)
 {
-  scm_t_rstate *state = scm_malloc (scm_the_rng.rstate_size);
-  if (state == 0)
-    scm_memory_error ("rstate");
+  scm_t_rstate *state;
+
+  state = scm_gc_malloc_pointerless (scm_the_rng.rstate_size,
+                                    "random-state");
   state->reserved0 = 0;
   scm_the_rng.init_rstate (state, seed, n);
   return state;
@@ -317,18 +320,12 @@ make_rstate (scm_t_rstate *state)
   SCM_RETURN_NEWSMOB (scm_tc16_rstate, state);
 }
 
-static size_t
-rstate_free (SCM rstate)
-{
-  free (SCM_RSTATE (rstate));
-  return 0;
-}
 
 /*
  * Scheme level interface.
  */
 
-SCM_GLOBAL_VARIABLE_INIT (scm_var_random_state, "*random-state*", scm_seed_to_random_state (scm_makfrom0str ("URL:http://stat.fsu.edu/~geo/diehard.html")));
+SCM_GLOBAL_VARIABLE_INIT (scm_var_random_state, "*random-state*", scm_seed_to_random_state (scm_from_locale_string ("URL:http://stat.fsu.edu/~geo/diehard.html")));
 
 SCM_DEFINE (scm_random, "random", 1, 1, 0, 
             (SCM n, SCM state),
@@ -383,11 +380,15 @@ SCM_DEFINE (scm_seed_to_random_state, "seed->random-state", 1, 0, 0,
             "Return a new random state using @var{seed}.")
 #define FUNC_NAME s_scm_seed_to_random_state
 {
+  SCM res;
   if (SCM_NUMBERP (seed))
     seed = scm_number_to_string (seed, SCM_UNDEFINED);
   SCM_VALIDATE_STRING (1, seed);
-  return make_rstate (scm_c_make_rstate (SCM_STRING_CHARS (seed),
-                                        SCM_STRING_LENGTH (seed)));
+  res = make_rstate (scm_c_make_rstate (scm_i_string_chars (seed),
+                                       scm_i_string_length (seed)));
+  scm_remember_upto_here_1 (seed);
+  return res;
+  
 }
 #undef FUNC_NAME
 
@@ -419,37 +420,65 @@ SCM_DEFINE (scm_random_normal, "random:normal", 0, 1, 0,
 }
 #undef FUNC_NAME
 
-#if SCM_HAVE_ARRAYS
-
 static void
-vector_scale (SCM v, double c)
+vector_scale_x (SCM v, double c)
 {
-  int n = scm_to_int (scm_uniform_vector_length (v));
-  if (SCM_VECTORP (v))
-    while (--n >= 0)
-      SCM_REAL_VALUE (SCM_VELTS (v)[n]) *= c;
+  size_t n;
+  if (scm_is_simple_vector (v))
+    {
+      n = SCM_SIMPLE_VECTOR_LENGTH (v);
+      while (n-- > 0)
+       SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n)) *= c;
+    }
   else
-    while (--n >= 0)
-      ((double *) SCM_VELTS (v))[n] *= c;
+    {
+      /* must be a f64vector. */
+      scm_t_array_handle handle;
+      size_t i, len;
+      ssize_t inc;
+      double *elts;
+
+      elts = scm_f64vector_writable_elements (v, &handle, &len, &inc);
+
+      for (i = 0; i < len; i++, elts += inc)
+       *elts *= c;
+      
+      scm_array_handle_release (&handle);
+    }
 }
 
 static double
 vector_sum_squares (SCM v)
 {
   double x, sum = 0.0;
-  int n = scm_to_int (scm_uniform_vector_length (v));
-  if (SCM_VECTORP (v))
-    while (--n >= 0)
-      {
-       x = SCM_REAL_VALUE (SCM_VELTS (v)[n]);
-       sum += x * x;
-      }
+  size_t n;
+  if (scm_is_simple_vector (v))
+    {
+      n = SCM_SIMPLE_VECTOR_LENGTH (v);
+      while (n-- > 0)
+       {
+         x = SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n));
+         sum += x * x;
+       }
+    }
   else
-    while (--n >= 0)
-      {
-       x = ((double *) SCM_VELTS (v))[n];
-       sum += x * x;
-      }
+    {
+      /* must be a f64vector. */
+      scm_t_array_handle handle;
+      size_t i, len;
+      ssize_t inc;
+      const double *elts;
+
+      elts = scm_f64vector_elements (v, &handle, &len, &inc);
+
+      for (i = 0; i < len; i++, elts += inc)
+       {
+         x = *elts;
+         sum += x * x;
+       }
+
+      scm_array_handle_release (&handle);
+    }
   return sum;
 }
 
@@ -460,23 +489,21 @@ vector_sum_squares (SCM v)
  */
 SCM_DEFINE (scm_random_solid_sphere_x, "random:solid-sphere!", 1, 1, 0, 
             (SCM v, SCM state),
-            "Fills vect with inexact real random numbers\n"
-            "the sum of whose squares is less than 1.0.\n"
-            "Thinking of vect as coordinates in space of\n"
-            "dimension n = (vector-length vect), the coordinates\n"
-            "are uniformly distributed within the unit n-sphere.\n"
-            "The sum of the squares of the numbers is returned.")
+           "Fills @var{vect} with inexact real random numbers the sum of\n"
+           "whose squares is less than 1.0.  Thinking of @var{vect} as\n"
+           "coordinates in space of dimension @var{n} @math{=}\n"
+           "@code{(vector-length @var{vect})}, the coordinates are\n"
+           "uniformly distributed within the unit @var{n}-sphere.")
 #define FUNC_NAME s_scm_random_solid_sphere_x
 {
-  SCM_VALIDATE_VECTOR_OR_DVECTOR (1, v);
   if (SCM_UNBNDP (state))
     state = SCM_VARIABLE_REF (scm_var_random_state);
   SCM_VALIDATE_RSTATE (2, state);
   scm_random_normal_vector_x (v, state);
-  vector_scale (v,
-               pow (scm_c_uniform01 (SCM_RSTATE (state)),
-                    1.0 / scm_to_int (scm_uniform_vector_length (v)))
-               / sqrt (vector_sum_squares (v)));
+  vector_scale_x (v,
+                 pow (scm_c_uniform01 (SCM_RSTATE (state)),
+                      1.0 / scm_c_generalized_vector_length (v))
+                 / sqrt (vector_sum_squares (v)));
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -491,12 +518,11 @@ SCM_DEFINE (scm_random_hollow_sphere_x, "random:hollow-sphere!", 1, 1, 0,
             "unit n-sphere.")
 #define FUNC_NAME s_scm_random_hollow_sphere_x
 {
-  SCM_VALIDATE_VECTOR_OR_DVECTOR (1, v);
   if (SCM_UNBNDP (state))
     state = SCM_VARIABLE_REF (scm_var_random_state);
   SCM_VALIDATE_RSTATE (2, state);
   scm_random_normal_vector_x (v, state);
-  vector_scale (v, 1 / sqrt (vector_sum_squares (v)));
+  vector_scale_x (v, 1 / sqrt (vector_sum_squares (v)));
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -509,24 +535,37 @@ SCM_DEFINE (scm_random_normal_vector_x, "random:normal-vector!", 1, 1, 0,
             "(i.e., with mean 0 and variance 1).")
 #define FUNC_NAME s_scm_random_normal_vector_x
 {
-  int n;
-  SCM_VALIDATE_VECTOR_OR_DVECTOR (1, v);
+  long i;
+  scm_t_array_handle handle;
+  scm_t_array_dim *dim;
+
   if (SCM_UNBNDP (state))
     state = SCM_VARIABLE_REF (scm_var_random_state);
   SCM_VALIDATE_RSTATE (2, state);
-  n = scm_to_int (scm_uniform_vector_length (v));
-  if (SCM_VECTORP (v))
-    while (--n >= 0)
-      SCM_VECTOR_SET (v, n, scm_from_double (scm_c_normal01 (SCM_RSTATE (state))));
+
+  scm_generalized_vector_get_handle (v, &handle);
+  dim = scm_array_handle_dims (&handle);
+
+  if (scm_is_vector (v))
+    {
+      SCM *elts = scm_array_handle_writable_elements (&handle);
+      for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
+       *elts = scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
+    }
   else
-    while (--n >= 0)
-      ((double *) SCM_VELTS (v))[n] = scm_c_normal01 (SCM_RSTATE (state));
+    {
+      /* must be a f64vector. */
+      double *elts = scm_array_handle_f64_writable_elements (&handle);
+      for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
+       *elts = scm_c_normal01 (SCM_RSTATE (state));
+    }
+
+  scm_array_handle_release (&handle);
+
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
 
-#endif /* SCM_HAVE_ARRAYS */
-
 SCM_DEFINE (scm_random_exp, "random:exp", 0, 1, 0, 
             (SCM state),
            "Return an inexact real in an exponential distribution with mean\n"
@@ -556,7 +595,6 @@ scm_init_random ()
   scm_the_rng = rng;
   
   scm_tc16_rstate = scm_make_smob_type ("random-state", 0);
-  scm_set_smob_free (scm_tc16_rstate, rstate_free);
 
   for (m = 1; m <= 0x100; m <<= 1)
     for (i = m >> 1; i < m; ++i)