# HG changeset patch # User jwe # Date 815377297 0 # Node ID d0a45cb55b59e5fc61cb5f2c36e4e1c06798940c # Parent 65572455466f5efa789de3f63aefab4f736b2a76 [project @ 1995-11-03 05:41:37 by jwe] diff -r 65572455466f -r d0a45cb55b59 src/rand.cc --- a/src/rand.cc Thu Nov 02 13:06:41 1995 +0000 +++ b/src/rand.cc Fri Nov 03 05:41:37 1995 +0000 @@ -34,13 +34,19 @@ #include "gripes.h" #include "help.h" #include "tree-const.h" +#include "unwind-prot.h" #include "utils.h" -// Possible distributions of random numbers. -enum rand_dist { uniform, normal }; +// 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 rand_dist current_distribution = uniform; +static int current_distribution = uniform_dist; + +// Has the seed been set yet? +static int initialized = 0; extern "C" { @@ -53,6 +59,10 @@ int *F77_FCN (setall, SETALL) (const int&, const int&); int *F77_FCN (getsd, GETSD) (int&, int&); + + int *F77_FCN (setsd, SETSD) (const int&, const int&); + + int *F77_FCN (setcgn, SETCGN) (const int&); } static double @@ -87,15 +97,15 @@ u.d = val; int i0 = force_to_fit_range (u.i[0], 1, 2147483563); int i1 = force_to_fit_range (u.i[1], 1, 2147483399); - F77_FCN (setall, SETALL) (i0, i1); + F77_FCN (setsd, SETSD) (i0, i1); } static char * curr_rand_dist (void) { - if (current_distribution == uniform) + if (current_distribution == uniform_dist) return "uniform"; - else if (current_distribution == normal) + else if (current_distribution == normal_dist) return "normal"; else { @@ -104,66 +114,53 @@ } } -DEFUN_DLD_BUILTIN ("rand", Frand, Srand, 11, - "rand -- generate a random value\n\ -\n\ -rand (N) -- generate N x N matrix\n\ -rand (A) -- generate matrix the size of A\n\ -rand (N, M) -- generate N x M matrix\n\ -rand (\"dist\") -- get current distribution\n\ -rand (DISTRIBUTION) -- set distribution type (\"normal\" or \"uniform\"\n\ -rand (SEED) -- get current seed\n\ -rand (SEED, N) -- set seed") +// 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) +{ +#if 0 + int s0 = 1234567890; + int s1 = 123456789; +#else + 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; +#endif + + s0 = force_to_fit_range (s0, 1, 2147483563); + s1 = force_to_fit_range (s1, 1, 2147483399); + + F77_FCN (setall, SETALL) (s0, s1); + + initialized = 1; +} + +static Octave_object +do_rand (const Octave_object& args, int nargin) { Octave_object retval; - int nargin = args.length (); - - if (nargin > 2 || nargout > 1) - { - print_usage ("rand"); - return retval; - } - - static int initialized = 0; - if (! initialized) - { - // 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. - -#if 0 - int s0 = 1234567890; - int s1 = 123456789; -#else - 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; -#endif - s0 = force_to_fit_range (s0, 1, 2147483563); - s1 = force_to_fit_range (s1, 1, 2147483399); - - F77_FCN (setall, SETALL) (s0, s1); - initialized = 1; - } - int n = 0; int m = 0; + if (nargin == 0) { n = 1; m = 1; + goto gen_matrix; } else if (nargin == 1) @@ -185,9 +182,17 @@ retval(0) = d; } else if (strcmp (s_arg, "uniform") == 0) - current_distribution = uniform; + { + current_distribution = uniform_dist; + + F77_FCN (setcgn, SETCGN) (uniform_dist); + } else if (strcmp (s_arg, "normal") == 0) - current_distribution = normal; + { + current_distribution = normal_dist; + + F77_FCN (setcgn, SETCGN) (normal_dist); + } else error ("rand: unrecognized string argument"); } @@ -299,12 +304,12 @@ double val; switch (current_distribution) { - case uniform: + case uniform_dist: F77_FCN (dgenunf, DGENUNF) (0.0, 1.0, val); rand_mat.elem (i, j) = val; break; - case normal: + case normal_dist: F77_FCN (dgennor, DGENNOR) (0.0, 1.0, val); rand_mat.elem (i, j) = val; break; @@ -323,6 +328,84 @@ return retval; } +DEFUN_DLD_BUILTIN ("rand", Frand, Srand, 11, + "rand -- generate a random value from a uniform distribution\n\ +\n\ +rand (N) -- generate N x N matrix\n\ +rand (size (A)) -- generate matrix the size of A\n\ +rand (N, M) -- generate N x M matrix\n\ +rand (SEED) -- get current seed\n\ +rand (SEED, N) -- set seed\n\ +\n\ +See also: randn") +{ + Octave_object retval; + + int nargin = args.length (); + + if (nargin > 2 || nargout > 1) + print_usage ("rand"); + else + { + if (! initialized) + do_initialization (); + + retval = do_rand (args, nargin); + } + + return retval; +} + +static void +reset_rand_generator (void *) +{ + F77_FCN (setcgn, SETCGN) (current_distribution); +} + +DEFUN_DLD_BUILTIN ("randn", Frandn, Srandn, 11, + "randn -- generate a random value from a normal distribution\n\ +\n\ +randn (N) -- generate N x N matrix\n\ +randn (size (A)) -- generate matrix the size of A\n\ +randn (N, M) -- generate N x M matrix\n\ +randn (SEED) -- get current seed\n\ +randn (SEED, N) -- set seed\n\ +\n\ +See also: rand") +{ + Octave_object retval; + + int nargin = args.length (); + + if (nargin > 2 || nargout > 1) + print_usage ("randn"); + else + { + if (! initialized) + do_initialization (); + + begin_unwind_frame ("randn"); + + // This relies on the fact that elements are popped from the + // unwind stack in the reverse of the order they are pushed + // (i.e. current_distribution will be reset before calling + // reset_rand_generator()). + + add_unwind_protect (reset_rand_generator, 0); + unwind_protect_int (current_distribution); + + current_distribution = normal_dist; + + F77_FCN (setcgn, SETCGN) (normal_dist); + + retval = do_rand (args, nargin); + + run_unwind_frame ("randn"); + } + + return retval; +} + /* ;;; Local Variables: *** ;;; mode: C++ ***