# HG changeset patch # User Rik # Date 1409355011 25200 # Node ID 83b88e20e9c1da03512a5f44a0b3b8510167ba45 # Parent 13fa7b5375a90880fce92df9a45ad3c0b454d13c nchoosek.m: Overhaul function. * nchoosek.m: Update docstring. Use same variable names in function as in documentation for clarity. Improve input validation. Don't manually clear variables at end of function which will go out of scope anyways and the memory reclaimed. Update built-in self tests. diff -r 13fa7b5375a9 -r 83b88e20e9c1 doc/interpreter/tips.txi --- a/doc/interpreter/tips.txi Fri Aug 29 13:27:36 2014 -0700 +++ b/doc/interpreter/tips.txi Fri Aug 29 16:30:11 2014 -0700 @@ -500,7 +500,8 @@ @@deftypefn @{Function File@} @{@@var@{c@} =@} nchoosek (@@var@{n@}, @@var@{k@}) @@deftypefnx @{Function File@} @{@@var@{c@} =@} nchoosek (@@var@{set@}, @@var@{k@}) -Compute the binomial coefficient or all combinations of a set of items. +Compute the binomial coefficient of @@var@{n@} or list all possible +combinations of a @@var@{set@} of items. If @@var@{n@} is a scalar then calculate the binomial coefficient of @@var@{n@} and @@var@{k@} which is defined as @@ -554,10 +555,10 @@ @@end group @@end example -@@code@{nchoosek@} works only for non-negative, integer arguments. Use -@@code@{bincoeff@} for non-integer and negative scalar arguments, or for -computing many binomial coefficients at once with vector inputs -for @@var@{n@} or @@var@{k@}. +Programming Note: When calculating the binomial coefficient @@code@{nchoosek@} +works only for non-negative, integer arguments. Use @@code@{bincoeff@} for +non-integer and negative scalar arguments, or for computing many binomial +coefficients at once with vector inputs for @@var@{n@} or @@var@{k@}. @@seealso@{bincoeff, perms@} @@end deftypefn @@ -566,7 +567,7 @@ @noindent which demonstrates most of the concepts discussed above. @iftex -This documentation string renders as +This documentation string renders in Info format as @c Note: use the actual output of info below, rather than try and @c reproduce it here to prevent it looking different from how it would @c appear with info. @@ -574,8 +575,8 @@ @example -- Function File: C = nchoosek (N, K) -- Function File: C = nchoosek (SET, K) - Compute the binomial coefficient or all combinations of a set of - items. + Compute the binomial coefficient of N or list all possible + combinations of a SET of items. If N is a scalar then calculate the binomial coefficient of N and K which is defined as @@ -608,32 +609,31 @@ 1 3 2 3 + Programming Note: When calculating the binomial coefficient `nchoosek' works only for non-negative, integer arguments. Use `bincoeff' for non-integer and negative scalar arguments, or for computing many binomial coefficients at once with vector inputs for N or K. - See also: bincoeff, perms + See also: bincoeff, perms. @end example @noindent -using info, whereas in a printed documentation using @TeX{} it will -appear as +whereas in printed documentation using @TeX{} it will appear as @deftypefn {Function File} {@var{c} =} nchoosek (@var{n}, @var{k}) @deftypefnx {Function File} {@var{c} =} nchoosek (@var{set}, @var{k}) -Compute the binomial coefficient or all combinations of a set of items. +Compute the binomial coefficient of @var{n} or list all possible +combinations of a @var{set} of items. If @var{n} is a scalar then calculate the binomial coefficient of @var{n} and @var{k} which is defined as - @tex $$ {n \choose k} = {n (n-1) (n-2) \cdots (n-k+1) \over k!} = {n! \over k! (n-k)!} $$ @end tex - @noindent This is the number of combinations of @var{n} items taken in groups of size @var{k}. @@ -665,10 +665,10 @@ @end group @end example -@code{nchoosek} works only for non-negative, integer arguments. Use -@code{bincoeff} for non-integer and negative scalar arguments, or for -computing many binomial coefficients at once with vector inputs for @var{n} -or @var{k}. +Programming Note: When calculating the binomial coefficient @code{nchoosek} +works only for non-negative, integer arguments. Use @code{bincoeff} for +non-integer and negative scalar arguments, or for computing many binomial +coefficients at once with vector inputs for @var{n} or @var{k}. @seealso{bincoeff, perms} @end deftypefn diff -r 13fa7b5375a9 -r 83b88e20e9c1 scripts/specfun/nchoosek.m --- a/scripts/specfun/nchoosek.m Fri Aug 29 13:27:36 2014 -0700 +++ b/scripts/specfun/nchoosek.m Fri Aug 29 16:30:11 2014 -0700 @@ -21,7 +21,8 @@ ## @deftypefn {Function File} {@var{c} =} nchoosek (@var{n}, @var{k}) ## @deftypefnx {Function File} {@var{c} =} nchoosek (@var{set}, @var{k}) ## -## Compute the binomial coefficient or all combinations of a set of items. +## Compute the binomial coefficient of @var{n} or list all possible +## combinations of a @var{set} of items. ## ## If @var{n} is a scalar then calculate the binomial coefficient ## of @var{n} and @var{k} which is defined as @@ -75,10 +76,10 @@ ## @end group ## @end example ## -## @code{nchoosek} works only for non-negative, integer arguments. Use -## @code{bincoeff} for non-integer and negative scalar arguments, or for -## computing many binomial coefficients at once with vector inputs -## for @var{n} or @var{k}. +## Programming Note: When calculating the binomial coefficient @code{nchoosek} +## works only for non-negative, integer arguments. Use @code{bincoeff} for +## non-integer and negative scalar arguments, or for computing many binomial +## coefficients at once with vector inputs for @var{n} or @var{k}. ## ## @seealso{bincoeff, perms} ## @end deftypefn @@ -87,16 +88,17 @@ ## Author: Paul Kienzle ## Author: Jaroslav Hajek -function A = nchoosek (v, k) +function C = nchoosek (v, k) if (nargin != 2 - || !isnumeric (k) || !isnumeric (v) - || !isscalar (k) || ! (isscalar (v) || isvector (v))) + || ! (isreal (k) && isscalar (k)) + || ! (isnumeric (v) && isvector (v))) print_usage (); endif - if (k < 0 || k != fix (k) - || (isscalar (v) && (v < k || v < 0 || v != fix (v)))) - error ("nchoosek: args are non-negative integers with V not less than K"); + if (k < 0 || k != fix (k)) + error ("nchoosek: K must be an integer >= 0"); + elseif (isscalar (v) && (iscomplex (v) || v < k || v < 0 || v != fix (v))) + error ("nchoosek: N must be a non-negative integer >= K"); endif n = length (v); @@ -104,39 +106,39 @@ if (n == 1) ## Improve precision at next step. k = min (k, v-k); - A = round (prod ((v-k+1:v)./(1:k))); - if (A*2*k*eps >= 0.5) - warning ("nchoosek", "nchoosek: possible loss of precision"); + C = round (prod ((v-k+1:v)./(1:k))); + if (C*2*k*eps >= 0.5) + warning ("nchoosek: possible loss of precision"); endif elseif (k == 0) - A = zeros (1,0); + C = zeros (1,0); elseif (k == 1) - A = v(:); + C = v(:); elseif (k == n) - A = v(:).'; + C = v(:).'; elseif (k > n) - A = zeros (0, k, class (v)); + C = zeros (0, k, class (v)); elseif (k == 2) ## Can do it without transpose. x = repelems (v(1:n-1), [1:n-1; n-1:-1:1]).'; y = cat (1, cellslices (v(:), 2:n, n*ones (1, n-1)){:}); - A = [x, y]; + C = [x, y]; elseif (k < n) v = v(:).'; - A = v(k:n); + C = v(k:n); l = 1:n-k+1; for j = 2:k - c = columns (A); - cA = cellslices (A, l, c*ones (1, n-k+1), 2); + c = columns (C); + cA = cellslices (C, l, c*ones (1, n-k+1), 2); l = c-l+1; b = repelems (v(k-j+1:n-j+1), [1:n-k+1; l]); - A = [b; cA{:}]; + C = [b; cA{:}]; l = cumsum (l); l = [1, 1 + l(1:n-k)]; endfor - clear cA b; - A = A.'; + C = C.'; endif + endfunction @@ -145,14 +147,19 @@ %!assert (size (nchoosek (1:5,0)), [1 0]) %% Test input validation -%!warning nchoosek (100,45); +%!error nchoosek () +%!error nchoosek (1) +%!error nchoosek (1,2,3) + +%!error nchoosek (100, 2i) +%!error nchoosek (100, [2 3]) %!error nchoosek ("100", 45) -%!error nchoosek (100, "45") -%!error nchoosek (100, ones (2,2)) -%!error nchoosek (repmat (100, [2 2]), 45) -%!error nchoosek (100, -45) -%!error nchoosek (100, 45.5) -%!error nchoosek (100, 145) -%!error nchoosek (-100, 45) -%!error nchoosek (100.5, 45) +%!error nchoosek (100*ones (2, 2), 45) +%!error nchoosek (100, -45) +%!error nchoosek (100, 45.5) +%!error nchoosek (100i, 2) +%!error nchoosek (100, 145) +%!error nchoosek (-100, 45) +%!error nchoosek (100.5, 45) +%!warning nchoosek (100, 45);