Mercurial > octave
diff src/DLD-FUNCTIONS/rand.cc @ 5730:109fdf7b3dcb
[project @ 2006-04-03 19:18:26 by jwe]
author | jwe |
---|---|
date | Mon, 03 Apr 2006 19:18:26 +0000 |
parents | cf44c749ba52 |
children | 8d7162924bd3 |
line wrap: on
line diff
--- a/src/DLD-FUNCTIONS/rand.cc Mon Apr 03 19:03:31 2006 +0000 +++ b/src/DLD-FUNCTIONS/rand.cc Mon Apr 03 19:18:26 2006 +0000 @@ -42,28 +42,56 @@ #include "utils.h" static octave_value -do_rand (const octave_value_list& args, int nargin, const char *fcn) +do_rand (const octave_value_list& args, int nargin, const char *fcn, + bool additional_arg = false) { octave_value retval; + NDArray a; + int idx = 0; + dim_vector dims; - dim_vector dims; + if (additional_arg) + { + if (nargin == 0) + { + error ("%s: expecting at least one argument", fcn); + goto done; + } + else if (args(0).is_string()) + additional_arg = false; + else + { + a = args(0).array_value (); + if (error_state) + { + error ("%s: expecting scalar or matrix arguments", fcn); + goto done; + } + idx++; + nargin--; + } + } switch (nargin) { case 0: { - dims.resize (2); + if (additional_arg) + dims = a.dims (); + else + { + dims.resize (2); - dims(0) = 1; - dims(1) = 1; - + dims(0) = 1; + dims(1) = 1; + } goto gen_matrix; } break; case 1: { - octave_value tmp = args(0); + octave_value tmp = args(idx); if (tmp.is_string ()) { @@ -73,10 +101,14 @@ { retval = octave_rand::distribution (); } - else if (s_arg == "seed" || s_arg == "state") + else if (s_arg == "seed") { retval = octave_rand::seed (); } + else if (s_arg == "state" || s_arg == "twister") + { + retval = octave_rand::state (); + } else if (s_arg == "uniform") { octave_rand::uniform_distribution (); @@ -85,6 +117,18 @@ { octave_rand::normal_distribution (); } + else if (s_arg == "exponential") + { + octave_rand::exponential_distribution (); + } + else if (s_arg == "poisson") + { + octave_rand::poisson_distribution (); + } + else if (s_arg == "gamma") + { + octave_rand::gamma_distribution (); + } else error ("%s: unrecognized string argument", fcn); } @@ -176,19 +220,27 @@ default: { - octave_value tmp = args(0); + octave_value tmp = args(idx); if (nargin == 2 && tmp.is_string ()) { std::string ts = tmp.string_value (); - if (ts == "seed" || ts == "state") + if (ts == "seed") { - double d = args(1).double_value (); + double d = args(idx+1).double_value (); if (! error_state) octave_rand::seed (d); } + else if (ts == "state" || ts == "twister") + { + ColumnVector s = + ColumnVector (args(idx+1).vector_value(false, true)); + + if (! error_state) + octave_rand::state (s); + } else error ("%s: unrecognized string argument", fcn); } @@ -198,7 +250,7 @@ for (int i = 0; i < nargin; i++) { - dims(i) = (octave_idx_type)args(i).int_value (); + dims(i) = (octave_idx_type)args(idx+i).int_value (); if (error_state) { @@ -221,33 +273,97 @@ dims.chop_trailing_singletons (); - return octave_rand::nd_array (dims); + if (additional_arg) + { + if (a.length() == 1) + return octave_rand::nd_array (dims, a(0)); + else + { + if (a.dims() != dims) + { + error ("%s: mismatch in argument size", fcn); + return retval; + } + octave_idx_type len = a.length (); + NDArray m (dims); + double *v = m.fortran_vec (); + for (octave_idx_type i = 0; i < len; i++) + v[i] = octave_rand::scalar (a(i)); + return m; + } + } + else + return octave_rand::nd_array (dims); } DEFUN_DLD (rand, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} rand (@var{x})\n\ @deftypefnx {Loadable Function} {} rand (@var{n}, @var{m})\n\ -@deftypefnx {Loadable Function} {} rand (@code{\"seed\"}, @var{x})\n\ +@deftypefnx {Loadable Function} {} rand (\"state\", @var{x})\n\ +@deftypefnx {Loadable Function} {} rand (\"seed\", @var{x})\n\ Return a matrix with random elements uniformly distributed on the\n\ interval (0, 1). The arguments are handled the same as the arguments\n\ -for @code{eye}. In\n\ -addition, you can set the seed for the random number generator using the\n\ +for @code{eye}.\n\ +\n\ +You can query the state of the random number generator using the\n\ form\n\ \n\ @example\n\ -rand (\"seed\", @var{x})\n\ +v = rand (\"state\")\n\ +@end example\n\ +\n\ +This returns a column vector @var{v} of length 625. Later, you can\n\ +restore the random number generator to the state @var{v}\n\ +using the form\n\ +\n\ +@example\n\ +rand (\"state\", v)\n\ @end example\n\ \n\ @noindent\n\ -where @var{x} is a scalar value. If called as\n\ +You may also initialize the state vector from an arbitrary vector of\n\ +length <= 625 for @var{v}. This new state will be a hash based on the\n\ +the value of @var{v}, not @var{v} itself.\n\ +\n\ +By default, the generator is initialized from @code{/dev/urandom} if it is\n\ +available, otherwise from cpu time, wall clock time and the current\n\ +fraction of a second.\n\ +\n\ +@code{rand} uses the Mersenne Twister with a period of 2^19937-1\n\ +(See M. Matsumoto and T. Nishimura, ``Mersenne Twister: A 623-dimensionally\n\ +equidistributed uniform pseudorandom number generator'', ACM Trans. on\n\ +Modeling and Computer Simulation Vol. 8, No. 1, Januray pp.3-30 1998,\n\ +@url{http://www.math.keio.ac.jp/~matumoto/emt.html}).\n\ +Do NOT use for CRYPTOGRAPHY without securely hashing several returned\n\ +values together, otherwise the generator state can be learned after\n\ +reading 624 consecutive values.\n\ +\n\ +@code{rand} includes a second random number generator, that was the\n\ +previous generator used in octave. The new generator is used by default\n\ +as it is significantly faster than the old generator, and produces\n\ +random numebrs with a significantly longer cycle time. However, in\n\ +some circumstances it might be desireable to obtain the same random\n\ +sequences as used by the old generators. To do this the keyword\n\ +\"seed\" is used to specify that the old generators should be use,\n\ +as in\n\ \n\ @example\n\ -rand (\"seed\")\n\ +rand (\"seed\", val)\n\ @end example\n\ \n\ -@noindent\n\ -@code{rand} returns the current value of the seed.\n\ +which sets the seed of the generator to @var{val}. The seed of the\n\ +generator can be queried with\n\ +\n\ +@example\n\ +s = rand (\"seed\")\n\ +@end example\n\ +\n\ +However, it should be noted that querying the seed will not cause\n\ +@code{rand} to use the old generators, only setting the seed will.\n\ +To cause @code{rand} to once again use the new generators, the\n\ +keyword \"state\" should be used to reset the state of the @code{rand}.\n\ +@seealso{randn,rande,randg,randp}\n\ @end deftypefn") { octave_value retval; @@ -259,6 +375,64 @@ return retval; } +/* +%!test # 'state' can be a scalar +%! rand('state',12); x = rand(1,4); +%! rand('state',12); y = rand(1,4); +%! assert(x,y); +%!test # 'state' can be a vector +%! rand('state',[12,13]); x=rand(1,4); +%! rand('state',[12;13]); y=rand(1,4); +%! assert(x,y); +%!test # querying 'state' doesn't disturb sequence +%! rand('state',12); rand(1,2); x=rand(1,2); +%! rand('state',12); rand(1,2); +%! s=rand('state'); y=rand(1,2); +%! assert(x,y); +%! rand('state',s); z=rand(1,2); +%! assert(x,z); +%!test # 'seed' must be a scalar +%! rand('seed',12); x = rand(1,4); +%! rand('seed',12); y = rand(1,4); +%! assert(x,y); +%!error(rand('seed',[12,13])) +%!test # querying 'seed' returns a value which can be used later +%! s=rand('seed'); x=rand(1,2); +%! rand('seed',s); y=rand(1,2); +%! assert(x,y); +%!test # querying 'seed' doesn't disturb sequence +%! rand('seed',12); rand(1,2); x=rand(1,2); +%! rand('seed',12); rand(1,2); +%! s=rand('seed'); y=rand(1,2); +%! assert(x,y); +%! rand('seed',s); z=rand(1,2); +%! assert(x,z); +*/ + +/* +%!test +%! % statistical tests may fail occasionally. +%! rand("state",12); +%! x = rand(100000,1); +%! assert(max(x)<1.); %*** Please report this!!! *** +%! assert(min(x)>0.); %*** Please report this!!! *** +%! assert(mean(x),0.5,0.0024); +%! assert(var(x),1/48,0.0632); +%! assert(skewness(x),0,0.012); +%! assert(kurtosis(x),-6/5,0.0094); +%!test +%! % statistical tests may fail occasionally. +%! rand("seed",12); +%! x = rand(100000,1); +%! assert(max(x)<1.); %*** Please report this!!! *** +%! assert(min(x)>0.); %*** Please report this!!! *** +%! assert(mean(x),0.5,0.0024); +%! assert(var(x),1/48,0.0632); +%! assert(skewness(x),0,0.012); +%! assert(kurtosis(x),-6/5,0.0094); +*/ + + static std::string current_distribution = octave_rand::distribution (); static void @@ -271,25 +445,18 @@ "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} randn (@var{x})\n\ @deftypefnx {Loadable Function} {} randn (@var{n}, @var{m})\n\ -@deftypefnx {Loadable Function} {} randn (@code{\"seed\"}, @var{x})\n\ -Return a matrix with normally distributed random elements. The\n\ -arguments are handled the same as the arguments for @code{eye}. In\n\ -addition, you can set the seed for the random number generator using the\n\ -form\n\ -\n\ -@example\n\ -randn (\"seed\", @var{x})\n\ -@end example\n\ +@deftypefnx {Loadable Function} {} randn (\"state\", @var{x})\n\ +@deftypefnx {Loadable Function} {} randn (\"seed\", @var{x})\n\ +Return a matrix with normally distributed random elements. The\n\ +arguments are handled the same as the arguments for @code{rand}.\n\ \n\ -@noindent\n\ -where @var{x} is a scalar value. If called as\n\ +By default, @code{randn} uses a Marsaglia and Tsang Ziggurat technique to\n\ +transform from a uniform to a normal distribution. (G. Marsaglia and\n\ +W.W. Tsang, 'Ziggurat method for generating random variables',\n\ +J. Statistical Software, vol 5, 2000,\n\ +@url{http://www.jstatsoft.org/v05/i08/})\n\ \n\ -@example\n\ -randn (\"seed\")\n\ -@end example\n\ -\n\ -@noindent\n\ -@code{randn} returns the current value of the seed.\n\ +@seealso{rand,rande,randg,randp}\n\ @end deftypefn") { octave_value retval; @@ -318,6 +485,369 @@ } /* +%!test +%! % statistical tests may fail occasionally. +%! rand("state",12); +%! x = randn(100000,1); +%! assert(mean(x),0,0.01); +%! assert(var(x),1,0.02); +%! assert(skewness(x),0,0.02); +%! assert(kurtosis(x),0,0.04); +%!test +%! % statistical tests may fail occasionally. +%! rand("seed",12); +%! x = randn(100000,1); +%! assert(mean(x),0,0.01); +%! assert(var(x),1,0.02); +%! assert(skewness(x),0,0.02); +%! assert(kurtosis(x),0,0.04); +*/ + +DEFUN_DLD (rande, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} rande (@var{x})\n\ +@deftypefnx {Loadable Function} {} rande (@var{n}, @var{m})\n\ +@deftypefnx {Loadable Function} {} rande (\"state\", @var{x})\n\ +@deftypefnx {Loadable Function} {} rande (\"seed\", @var{x})\n\ +Return a matrix with exponentially distributed random elements. The\n\ +arguments are handled the same as the arguments for @code{rand}.\n\ +\n\ +By default, @code{randn} uses a Marsaglia and Tsang Ziggurat technique to\n\ +transform from a uniform to a exponential distribution. (G. Marsaglia and\n\ +W.W. Tsang, 'Ziggurat method for generating random variables',\n\ +J. Statistical Software, vol 5, 2000,\n\ +@url{http://www.jstatsoft.org/v05/i08/})\n\ +@seealso{rand,randn,randg,randp}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + unwind_protect::begin_frame ("rande"); + + // 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()). + + unwind_protect::add (reset_rand_generator, 0); + unwind_protect_str (current_distribution); + + current_distribution = "exponential"; + + octave_rand::distribution (current_distribution); + + retval = do_rand (args, nargin, "rande"); + + unwind_protect::run_frame ("rande"); + + return retval; +} + +/* +%!test +%! % statistical tests may fail occasionally +%! rand("state",12); +%! x = rande(100000,1); +%! assert(min(x)>0); % *** Please report this!!! *** +%! assert(mean(x),1,0.01); +%! assert(var(x),1,0.03); +%! assert(skewness(x),2,0.06); +%! assert(kurtosis(x),6,0.7); +%!test +%! % statistical tests may fail occasionally +%! rand("seed",12); +%! x = rande(100000,1); +%! assert(min(x)>0); % *** Please report this!!! *** +%! assert(mean(x),1,0.01); +%! assert(var(x),1,0.03); +%! assert(skewness(x),2,0.06); +%! assert(kurtosis(x),6,0.7); +*/ + +DEFUN_DLD (randg, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} randg (@var{a}, @var{x})\n\ +@deftypefnx {Loadable Function} {} randg (@var{a}, @var{n}, @var{m})\n\ +@deftypefnx {Loadable Function} {} randg (\"state\", @var{x})\n\ +@deftypefnx {Loadable Function} {} randg (\"seed\", @var{x})\n\ +Return a matrix with @code{gamma(@var{a},1)} distributed random elements.\n\ +The arguments are handled the same as the arguments for @code{rand},\n\ +except for the argument @var{a}.\n\ +\n\ +This can be used to generate many distributions:\n\ +\n\ +@table @asis\n\ +@item @code{gamma (a,b)} for @code{a > -1}, @code{b > 0}\n\ +@example\n\ +r = b*randg(a)\n\ +@end example\n\ +@item @code{beta(a,b)} for @code{a > -1}, @code{b > -1}\n\ +@example\n\ +r1 = randg(a,1)\n\ +r = r1 / (r1 + randg(b,1))\n\ +@end example\n\ +@item @code{Erlang(a, n)}\n\ +@example\n\ +r = a*randg(n)\n\ +@end example\n\ +@item @code{chisq(df)} for @code{df > 0}\n\ +@example\n\ +r = 2*randg(df/2)\n\ +@end example\n\ +@item @code{t(df)} for @code{0 < df < inf} (use randn if df is infinite)\n\ +@example\n\ +r = randn() / sqrt(2*randg(df/2)/df)\n\ +@end example\n\ +@item @code{F(n1,n2)} for @code{0 < n1}, @code{0 < n2}\n\ +@example\n\ +r1 = 2*randg(n1/2)/n1 or 1 if n1 is infinite\n\ +r2 = 2*randg(n2/2)/n2 or 1 if n2 is infinite\n\ +r = r1 / r2\n\n\ +@end example\n\ +@item negative @code{binomial (n, p)} for @code{n > 0}, @code{0 < p <= 1}\n\ +@example\n\ +r = randp((1-p)/p * randg(n))\n\ +@end example\n\ +@item non-central @code{chisq(df,L)}, for @code{df >= 0} and @code{L > 0}\n\ +(use chisq if @code{L = 0})\n\ +@example\n\ +r = randp(L/2)\n\ +r(r > 0) = 2*randg(r(r > 0))\n\ +r(df > 0) += 2*randg(df(df > 0)/2)\n\ +@end example\n\ +@item @code{Dirichlet(a1,...,ak)}\n\ +@example\n\ +r = (randg(a1),...,randg(ak))\n\ +r = r / sum(r)\n\ +@end example\n\ +@end table\n\ +@seealso{rand,randn,rande,randp}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin < 1) + error ("randg: insufficient arguments"); + else + { + unwind_protect::begin_frame ("randg"); + + // 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()). + + unwind_protect::add (reset_rand_generator, 0); + unwind_protect_str (current_distribution); + + current_distribution = "gamma"; + + octave_rand::distribution (current_distribution); + + retval = do_rand (args, nargin, "randg", true); + + unwind_protect::run_frame ("randg"); + } + + return retval; +} + +/* +%!test +%! rand("state",12) +%!assert(randg([-inf,-1,0,inf,nan]),[nan,nan,nan,nan,nan]) % *** Please report +%!test +%! % statistical tests may fail occasionally. +%! a=0.1; x = randg(a,100000,1); +%! assert(mean(x), a, 0.01); +%! assert(var(x), a, 0.01); +%! assert(skewness(x),2/sqrt(a), 1.); +%! assert(kurtosis(x),6/a, 50.); +%!test +%! % statistical tests may fail occasionally. +%! a=0.95; x = randg(a,100000,1); +%! assert(mean(x), a, 0.01); +%! assert(var(x), a, 0.04); +%! assert(skewness(x),2/sqrt(a), 0.2); +%! assert(kurtosis(x),6/a, 2.); +%!test +%! % statistical tests may fail occasionally. +%! a=1; x = randg(a,100000,1); +%! assert(mean(x),a, 0.01); +%! assert(var(x),a, 0.04); +%! assert(skewness(x),2/sqrt(a), 0.2); +%! assert(kurtosis(x),6/a, 2.); +%!test +%! % statistical tests may fail occasionally. +%! a=10; x = randg(a,100000,1); +%! assert(mean(x), a, 0.1); +%! assert(var(x), a, 0.5); +%! assert(skewness(x),2/sqrt(a), 0.1); +%! assert(kurtosis(x),6/a, 0.5); +%!test +%! % statistical tests may fail occasionally. +%! a=100; x = randg(a,100000,1); +%! assert(mean(x), a, 0.2); +%! assert(var(x), a, 2.); +%! assert(skewness(x),2/sqrt(a), 0.05); +%! assert(kurtosis(x),6/a, 0.2); +%!test +%! rand("seed",12) +%!assert(randg([-inf,-1,0,inf,nan]),[nan,nan,nan,nan,nan]) % *** Please report +%!test +%! % statistical tests may fail occasionally. +%! a=0.1; x = randg(a,100000,1); +%! assert(mean(x), a, 0.01); +%! assert(var(x), a, 0.01); +%! assert(skewness(x),2/sqrt(a), 1.); +%! assert(kurtosis(x),6/a, 50.); +%!test +%! % statistical tests may fail occasionally. +%! a=0.95; x = randg(a,100000,1); +%! assert(mean(x), a, 0.01); +%! assert(var(x), a, 0.04); +%! assert(skewness(x),2/sqrt(a), 0.2); +%! assert(kurtosis(x),6/a, 2.); +%!test +%! % statistical tests may fail occasionally. +%! a=1; x = randg(a,100000,1); +%! assert(mean(x),a, 0.01); +%! assert(var(x),a, 0.04); +%! assert(skewness(x),2/sqrt(a), 0.2); +%! assert(kurtosis(x),6/a, 2.); +%!test +%! % statistical tests may fail occasionally. +%! a=10; x = randg(a,100000,1); +%! assert(mean(x), a, 0.1); +%! assert(var(x), a, 0.5); +%! assert(skewness(x),2/sqrt(a), 0.1); +%! assert(kurtosis(x),6/a, 0.5); +%!test +%! % statistical tests may fail occasionally. +%! a=100; x = randg(a,100000,1); +%! assert(mean(x), a, 0.2); +%! assert(var(x), a, 2.); +%! assert(skewness(x),2/sqrt(a), 0.05); +%! assert(kurtosis(x),6/a, 0.2); +*/ + + +DEFUN_DLD (randp, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} randp (@var{l}, @var{x})\n\ +@deftypefnx {Loadable Function} {} randp (@var{l}, @var{n}, @var{m})\n\ +@deftypefnx {Loadable Function} {} randp (\"state\", @var{x})\n\ +@deftypefnx {Loadable Function} {} randp (\"seed\", @var{x})\n\ +Return a matrix with Poisson distributed random elements. The arguments\n\ +are handled the same as the arguments for @code{rand}, except for the\n\ +argument @var{l}.\n\ +\n\ +Five different algorithms are used depending on the range of @var{l}\n\ +and whether or not @var{l} is a scalar or a matrix.\n\ +\n\ +@table @asis\n\ +@item For scalar @var{l} <= 12, use direct method.\n\ +Press, et al., 'Numerical Recipes in C', Cambridge University Press, 1992.\n\ +@item For scalar @var{l} > 12, use rejection method.[1]\n\ +Press, et al., 'Numerical Recipes in C', Cambridge University Press, 1992.\n\ +@item For matrix @var{l} <= 10, use inversion method.[2]\n\ +Stadlober E., et al., WinRand source code, available via FTP.\n\ +@item For matrix @var{l} > 10, use patchwork rejection method.\n\ +Stadlober E., et al., WinRand source code, available via FTP, or\n\ +H. Zechner, 'Efficient sampling from continuous and discrete\n\ +unimodal distributions', Doctoral Dissertaion, 156pp., Technical\n\ +University Graz, Austria, 1994.\n\ +@item For @var{l} > 1e8, use normal approximation.\n\ +L. Montanet, et al., 'Review of Particle Properties', Physical Review\n\ +D 50 p1284, 1994\n\ +@end table\n\ +@seealso{rand,randn,rande,randg}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin < 1) + error ("randp: insufficient arguments"); + else + { + unwind_protect::begin_frame ("randp"); + + // 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()). + + unwind_protect::add (reset_rand_generator, 0); + unwind_protect_str (current_distribution); + + current_distribution = "poisson"; + + octave_rand::distribution (current_distribution); + + retval = do_rand (args, nargin, "randp", true); + + unwind_protect::run_frame ("randp"); + } + + return retval; +} + +/* +%!test +%! rand("state",12) +%!assert(randp([-inf,-1,0,inf,nan]),[nan,nan,0,nan,nan]); % *** Please report +%!test +%! % statistical tests may fail occasionally. +%! for a=[5 15] +%! x = randp(a,100000,1); +%! assert(min(x)>=0); % *** Please report this!!! *** +%! assert(mean(x),a,0.03); +%! assert(var(x),a,0.2); +%! assert(skewness(x),1/sqrt(a),0.03); +%! assert(kurtosis(x),1/a,0.08); +%! end +%!test +%! % statistical tests may fail occasionally. +%! for a=[5 15] +%! x = randp(a*ones(100000,1),100000,1); +%! assert(min(x)>=0); % *** Please report this!!! *** +%! assert(mean(x),a,0.03); +%! assert(var(x),a,0.2); +%! assert(skewness(x),1/sqrt(a),0.03); +%! assert(kurtosis(x),1/a,0.08); +%! end +%!test +%! rand("seed",12) +%!assert(randp([-inf,-1,0,inf,nan]),[nan,nan,0,nan,nan]); % *** Please report +%!test +%! % statistical tests may fail occasionally. +%! for a=[5 15] +%! x = randp(a,100000,1); +%! assert(min(x)>=0); % *** Please report this!!! *** +%! assert(mean(x),a,0.03); +%! assert(var(x),a,0.2); +%! assert(skewness(x),1/sqrt(a),0.03); +%! assert(kurtosis(x),1/a,0.08); +%! end +%!test +%! % statistical tests may fail occasionally. +%! for a=[5 15] +%! x = randp(a*ones(100000,1),100000,1); +%! assert(min(x)>=0); % *** Please report this!!! *** +%! assert(mean(x),a,0.03); +%! assert(var(x),a,0.2); +%! assert(skewness(x),1/sqrt(a),0.03); +%! assert(kurtosis(x),1/a,0.08); +%! end +*/ + +/* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: ***