Mercurial > octave
changeset 27252:23523700b6b8
polyval.m: Overhaul input validation (bug #56632).
* polyval.m: Use spaces in formulas in docstring for readability.
Use isfloat to require that inputs be floating point numeric (Matlab
compatibility). Move all input validation to start of function.
Return output which is of the same type as the input ("single" or "double")
even in cases of an empty input. Use numel instead of length.
Eliminate unnecessary try/catch block. Update and add more BIST tests.
author | Rik <rik@octave.org> |
---|---|
date | Mon, 15 Jul 2019 13:04:31 -0700 |
parents | 42fd0e3121f7 |
children | e3d886685813 |
files | scripts/polynomial/polyval.m |
diffstat | 1 files changed, 62 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/polynomial/polyval.m Sat Jul 13 15:24:57 2019 -0700 +++ b/scripts/polynomial/polyval.m Mon Jul 15 13:04:31 2019 -0700 @@ -28,7 +28,7 @@ ## the elements of @var{x}. ## ## When @var{mu} is present, evaluate the polynomial for -## (@var{x}-@var{mu}(1))/@var{mu}(2). +## @w{(@var{x} - @var{mu}(1)) / @var{mu}(2)}. ## ## In addition to evaluating the polynomial, the second output represents the ## prediction interval, @var{y} +/- @var{dy}, which contains at least 50% of @@ -49,50 +49,60 @@ print_usage (); endif - if (isempty (x)) - y = x; + ## Algorithm requires floating point values + if (! isfloat (p) || (! isvector (p) && ! isempty (p))) + error ("polyval: P must be a numeric floating point vector"); + endif + if (! isfloat (x)) + error ("polyval: X must be numeric floating point"); + endif + + if (nargout > 1) + if (isempty (s)) + error ("polyval: S input is required for DY output argument"); + elseif (isstruct (s)) + if (! all (ismember ({"R", "normr", "df"}, fieldnames (s)))) + error ("polyval: S input is missing required fields"); + endif + else + error ("polyval: S input must be a structure"); + endif + endif + + if (nargin == 4 && (! isfloat (mu) || numel (mu) < 2)) + error ("polyval: MU must be numeric floating point with 2 values"); + endif + + if (isempty (p) || isempty (x)) + if (isa (p, "single") || isa (x, "single")) + y = zeros (size (x), "single"); + else + y = zeros (size (x)); + endif return; - elseif (isempty (p)) - y = zeros (size (x)); - return; - elseif (! isvector (p)) - error ("polyval: P must be a vector"); endif if (nargin == 4) x = (x - mu(1)) / mu(2); endif - n = length (p) - 1; - y = p(1) * ones (size (x)); + n = numel (p) - 1; + y = p(1) * ones (size (x), class (x)); for i = 2:n+1 y = y .* x + p(i); endfor - if (nargout == 2) + if (nargout > 1) ## Note: the F-Distribution is generally considered to be single-sided. ## http://www.itl.nist.gov/div898/handbook/eda/section3/eda3673.htm ## t = finv (1-alpha, s.df, s.df); ## dy = t * sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df) ## If my inference is correct, then t must equal 1 for polyval. ## This is because finv (0.5, n, n) = 1.0 for any n. - try - k = numel (x); - A = (x(:) * ones (1, n+1)) .^ (ones (k, 1) * (n:-1:0)); - dy = sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df); - dy = reshape (dy, size (x)); - catch - if (isempty (s)) - error ("polyval: S input is required for DY output argument"); - elseif (isstruct (s) - && all (ismember ({"R", "normr", "df"}, fieldnames (s)))) - error (lasterr ()); - elseif (isstruct (s)) - error ("polyval: S input is missing required fields"); - else - error ("polyval: S input must be a structure"); - endif - end_try_catch + k = numel (x); + A = (x(:) * ones (1, n+1)) .^ (ones (k, 1) * (n:-1:0)); + dy = sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df); + dy = reshape (dy, size (x)); endif endfunction @@ -149,17 +159,35 @@ %! assert (y, polyval (p,x), eps); %! x = reshape (x, [1, 1, 5, 2]); -%!assert (zeros (1, 10), polyval ([], 1:10)) -%!assert ([], polyval (1, [])) -%!assert ([], polyval ([], [])) -%!assert (zeros (0, 1), polyval (1, zeros (0,1))) +## Test empty combinations +%!assert (polyval ([], 1:10), zeros (1, 10)) +%!assert (class (polyval (single ([]), 1:10)), "single") +%!assert (class (polyval ([], single (1:10))), "single") +%!assert (polyval (1, []), []) +%!assert (polyval ([], []), []) +%!assert (polyval (1, zeros (0,3)), zeros (0, 3)) +%!assert (class (polyval (single (1), [])), "single") +%!assert (class (polyval (1, single ([]))), "single") +%!assert (class (polyval (single ([]), [])), "single") +%!assert (class (polyval ([], single ([]))), "single") ## Test input validation %!error polyval () %!error polyval (1) %!error polyval (1,2,3,4,5) -%!error <P must be a vector> polyval ([1,0;0,1],0:10) +%!error [y, dy] = polyval (1, 2) +%!error <P must be a numeric floating point vector> polyval ({1, 0}, 0:10) +%!error <P must be a numeric floating point vector> polyval (int8 ([1]), 0:10) +%!error <P must be a numeric floating point vector> polyval ([1,0;0,1], 0:10) +%!error <X must be numeric floating point> polyval ([1,0], {0:10}) +%!error <X must be numeric floating point> polyval ([1,0], int8 (0:10)) %!error <S input is required> [y, dy] = polyval (1, 1, []) %!error <S input is missing required fields> -%! [y, dy] = polyval (1, 1, struct ("T", 0, "normr", 1, "df", 2)) +%! [y, dy] = polyval (1, 1, struct ("T", 0, "normr", 1, "df", 2)); %!error <S input must be a structure> [y, dy] = polyval (1, 1, 2) +%!error <MU must be numeric floating point with 2 values> +%! polyval (1, 1, [], {1, 2}); +%!error <MU must be numeric floating point with 2 values> +%! polyval (1, 1, [], int8 ([1,2])); +%!error <MU must be numeric floating point with 2 values> +%! polyval (1, 1, [], [1]);