changeset 4308:b738d1a02adb

[project @ 2003-01-24 19:37:12 by jwe]
author jwe
date Fri, 24 Jan 2003 19:37:12 +0000
parents fd034cd46aea
children a9560cebae6e
files liboctave/oct-rand.cc liboctave/oct-rand.h
diffstat 2 files changed, 371 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/oct-rand.cc	Fri Jan 24 19:37:12 2003 +0000
@@ -0,0 +1,304 @@
+/*
+
+Copyright (C) 2003 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "f77-fcn.h"
+#include "lo-error.h"
+#include "oct-rand.h"
+
+// Possible distributions of random numbers.  This was handled with an
+// enum, but unwind_protecting that doesn't work so well.
+#define uniform_dist 1
+#define normal_dist 2
+
+// Current distribution of random numbers.
+static int current_distribution = uniform_dist;
+
+// Has the seed been set yet?
+static bool initialized = false;
+
+extern "C"
+{
+  int F77_FUNC (dgennor, DGENNOR) (const double&, const double&,
+				  double&);
+
+  int F77_FUNC (dgenunf, DGENUNF) (const double&, const double&,
+				  double&);
+
+  int F77_FUNC (setall, SETALL) (const int&, const int&);
+
+  int F77_FUNC (getsd, GETSD) (int&, int&);
+
+  int F77_FUNC (setsd, SETSD) (const int&, const int&);
+
+  int F77_FUNC (setcgn, SETCGN) (const int&);
+}
+
+static int
+force_to_fit_range (int i, int lo, int hi)
+{
+  assert (hi > lo && lo >= 0 && hi > lo);
+
+  i = i > 0 ? i : -i;
+
+  if (i < lo)
+    i = lo;
+  else if (i > hi)
+    i = i % hi;
+
+  return i;
+}
+
+// Make the random number generator give us a different sequence every
+// time we start octave unless we specifically set the seed.  The
+// technique used below will cycle monthly, but it it does seem to
+// work ok to give fairly different seeds each time Octave starts.
+
+static void
+do_initialization (void)
+{
+  time_t now;
+  struct tm *tm;
+ 
+  time (&now);
+  tm = localtime (&now);
+ 
+  int hour = tm->tm_hour + 1;
+  int minute = tm->tm_min + 1;
+  int second = tm->tm_sec + 1;
+
+  int s0 = tm->tm_mday * hour * minute * second;
+  int s1 = hour * minute * second;
+
+  s0 = force_to_fit_range (s0, 1, 2147483563);
+  s1 = force_to_fit_range (s1, 1, 2147483399);
+
+  F77_FUNC (setall, SETALL) (s0, s1);
+
+  initialized = true;
+}
+
+static inline void
+maybe_initialize (void)
+{
+  if (! initialized)
+    do_initialization ();
+}
+
+double
+octave_rand::seed (void)
+{
+  maybe_initialize ();
+
+  union d2i { double d; int i[2]; };
+  union d2i u;
+  F77_FUNC (getsd, GETSD) (u.i[0], u.i[1]);
+  return u.d;
+}
+
+void
+octave_rand::seed (double s)
+{
+  maybe_initialize ();
+
+  union d2i { double d; int i[2]; };
+  union d2i u;
+  u.d = s;
+  int i0 = force_to_fit_range (u.i[0], 1, 2147483563);
+  int i1 = force_to_fit_range (u.i[1], 1, 2147483399);
+  F77_FUNC (setsd, SETSD) (i0, i1);
+}
+
+std::string
+octave_rand::distribution (void)
+{
+  maybe_initialize ();
+
+  if (current_distribution == uniform_dist)
+    return "uniform";
+  else if (current_distribution == normal_dist)
+    return "normal";
+  else
+    {
+      abort ();
+      return "";
+    }
+}
+
+void
+octave_rand::distribution (const std::string& d)
+{
+  if (d == "uniform")
+    octave_rand::uniform_distribution ();
+  else if (d == "normal")
+    octave_rand::normal_distribution ();
+  else
+    (*current_liboctave_error_handler) ("rand: invalid distribution");
+}
+
+void
+octave_rand::uniform_distribution (void)
+{
+  maybe_initialize ();
+
+  current_distribution = uniform_dist;
+
+  F77_FUNC (setcgn, SETCGN) (uniform_dist);
+}
+
+void
+octave_rand::normal_distribution (void)
+{
+  maybe_initialize ();
+
+  current_distribution = normal_dist;
+
+  F77_FUNC (setcgn, SETCGN) (normal_dist);
+}
+
+double
+octave_rand::scalar (void)
+{
+  maybe_initialize ();
+
+  double retval = 0.0;
+
+  switch (current_distribution)
+    {
+    case uniform_dist:
+      F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, retval);
+      break;
+
+    case normal_dist:
+      F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, retval);
+      break;
+
+    default:
+      abort ();
+      break;
+    }
+
+  return retval;
+}
+
+#define MAKE_RAND_MAT(mat, nr, nc, f, F) \
+  do \
+    { \
+      double val; \
+      for (volatile int j = 0; j < nc; j++) \
+	for (volatile int i = 0; i < nr; i++) \
+	  { \
+	    OCTAVE_QUIT; \
+	    F77_FUNC (f, F) (0.0, 1.0, val); \
+	    mat(i,j) = val; \
+	  } \
+    } \
+  while (0)
+
+Matrix
+octave_rand::matrix (int n, int m)
+{
+  maybe_initialize ();
+
+  Matrix retval;
+
+  if (n >= 0 && m >= 0)
+    {
+      retval.resize (n, m);
+
+      if (n > 0 && m > 0)
+	{
+	  switch (current_distribution)
+	    {
+	    case uniform_dist:
+	      MAKE_RAND_MAT (retval, n, m, dgenunf, DGENUNF);
+	      break;
+
+	    case normal_dist:
+	      MAKE_RAND_MAT (retval, n, m, dgennor, DGENNOR);
+	      break;
+
+	    default:
+	      abort ();
+	      break;
+	    }
+	}
+    }
+  else
+    (*current_liboctave_error_handler) ("rand: invalid negative argument");
+
+  return retval;
+}
+
+#define MAKE_RAND_ARRAY(array, n, f, F) \
+  do \
+    { \
+      double val; \
+      for (volatile int i = 0; i < n; i++) \
+	{ \
+	  OCTAVE_QUIT; \
+	  F77_FUNC (f, F) (0.0, 1.0, val); \
+	  array(i) = val; \
+	} \
+    } \
+  while (0)
+
+Array<double>
+octave_rand::vector (int n)
+{
+  maybe_initialize ();
+
+  Array<double> retval;
+
+  if (n > 0)
+    {
+      retval.resize (n);
+
+      switch (current_distribution)
+	{
+	case uniform_dist:
+	  MAKE_RAND_ARRAY (retval, n, dgenunf, DGENUNF);
+	  break;
+
+	case normal_dist:
+	  MAKE_RAND_ARRAY (retval, n, dgennor, DGENNOR);
+	  break;
+
+	default:
+	  abort ();
+	  break;
+	}
+    }
+  else if (n < 0)
+    (*current_liboctave_error_handler) ("rand: invalid negative argument");
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/oct-rand.h	Fri Jan 24 19:37:12 2003 +0000
@@ -0,0 +1,67 @@
+/*
+
+Copyright (C) 2003 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_rand_h)
+#define octave_rand_h 1
+
+#include <string>
+
+#include "dMatrix.h"
+
+struct
+octave_rand
+{
+  // Return the current seed.
+  static double seed (void);
+
+  // Set the seed.
+  static void seed (double s);
+
+  // Return the current distribution.
+  static std::string distribution (void);
+
+  // Set the current distribution.  May be either "uniform" (the
+  // default) or "normal".
+  static void distribution (const std::string& d);
+
+  static void uniform_distribution (void);
+
+  static void normal_distribution (void);
+
+  // Return the next number from the sequence.
+  static double scalar (void);
+
+  // Return a matrix of numbers from the sequence, filled in column
+  // major order.
+  static Matrix matrix (int r, int c);
+
+  // Return an array of numbers from the sequence.
+  static Array<double> vector (int n);
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/