Mercurial > octave
changeset 23972:b4cf41d173dd
* cplxpair.m: Improve accuracy and compatibility (bug #50124)
author | Bill Lash |
---|---|
date | Tue, 29 Aug 2017 16:46:48 -0400 |
parents | 6cc3aafbdc41 |
children | a315ac23dc6c |
files | scripts/general/cplxpair.m |
diffstat | 1 files changed, 31 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/general/cplxpair.m Tue Aug 29 16:00:43 2017 -0400 +++ b/scripts/general/cplxpair.m Tue Aug 29 16:46:48 2017 -0400 @@ -65,10 +65,11 @@ return; endif + cls = ifelse (isa (z, "single"), "single", "double"); if (nargin < 2 || isempty (tol)) - tol = 100; - elseif (! isscalar (tol) || tol < 0) - error ("cplxpair: TOL must be a positive scalar number"); + tol = 100*eps(cls); + elseif (! isscalar (tol) || tol < 0 || tol >= 1) + error ("cplxpair: TOL must be a scalar number such that 0 <= TOL < 1"); endif nd = ndims (z); @@ -95,14 +96,18 @@ [q, idx] = sort (real (z), 1); z = z(idx + n * ones (n, 1) * [0:m-1]); + ## Put the purely real values at the end of the returned list. - cls = ifelse (isa (z, "single"), "single", "double"); [idxi, idxj] = find (abs (imag (z)) ./ (abs (z) + realmin (cls)) ... - < tol*eps (abs (z))); + <= tol); + ## Force values detected to be real within tolerance to actually be real. + z(idxi + n*(idxj-1)) = real (z(idxi + n*(idxj-1))); q = sparse (idxi, idxj, 1, n, m); nr = sum (q, 1); [q, idx] = sort (q, 1); - z = z(idx); + si = size(idx); + midx=idx+[0:si(2)-1]*si(1); + z = z(midx); y = z; ## For each remaining z, place the value and its conjugate at the start of @@ -113,16 +118,19 @@ if (i+1 > p) error ("cplxpair: could not pair all complex numbers"); endif - [v, idx] = min (abs (z(i+1:p) - conj (z(i)))); - if (v > tol*eps (abs (z(i)))) + [v, idx] = min (abs (z(i+1:p,j) - conj (z(i,j)))); + if (v >= tol*abs(z(i,j))) error ("cplxpair: could not pair all complex numbers"); endif - if (imag (z(i)) < 0) - y([i, i+1]) = z([i, idx+i]); + ## For pairs, select the one with positive imaginary part + ## and use it and it's conjugate, but the pair with negative + ## imaginary part first + if (imag (z(i,j)) > 0) + y([i, i+1],j) = [conj(z(i,j)), z(i,j)]; else - y([i, i+1]) = z([idx+i, i]); + y([i, i+1],j) = [conj(z(idx+i,j)), z(idx+i,j)]; endif - z(idx+i) = z(i+1); + z(idx+i,j) = z(i+1,j); endfor endfor @@ -144,14 +152,21 @@ %! [1-1i; 1+1i; 1-1i; 1+1i; 1; 2]) %!assert (cplxpair ([0, 1, 2]), [0, 1, 2]) -%!shared z +%!shared z,y %! z = exp (2i*pi*[4; 3; 5; 2; 6; 1; 0]/7); +%! z(2) = conj(z(1)); +%! z(4) = conj(z(3)); +%! z(6) = conj(z(5)); %!assert (cplxpair (z(randperm (7))), z) %!assert (cplxpair (z(randperm (7))), z) %!assert (cplxpair (z(randperm (7))), z) %!assert (cplxpair ([z(randperm (7)), z(randperm (7))]), [z,z]) %!assert (cplxpair ([z(randperm (7)), z(randperm (7))],[],1), [z,z]) %!assert (cplxpair ([z(randperm (7)).'; z(randperm (7)).'],[],2), [z.';z.']) +%! y = [ -1-1i; -1+1i;-3; -2; 1; 2; 3]; +%!assert (cplxpair ([z(randperm (7)), y(randperm (7))]), [z,y]) +%!assert (cplxpair ([z(randperm (7)), y(randperm (7)),z(randperm (7))]), [z,y,z]) + ## Test tolerance %!assert (cplxpair ([2000 * (1+eps) + 4j; 2000 * (1-eps) - 4j]), ... @@ -163,6 +178,7 @@ ## Test input validation %!error cplxpair () %!error cplxpair (1,2,3,4) -%!error <TOL must be .* positive> cplxpair (1, -1) -%!error <TOL must be .* scalar number> cplxpair (1, ones (2,2)) +%!error <cplxpair: TOL must be .* scalar number> cplxpair (1, -1) +%!error <cplxpair: TOL must be .* scalar number> cplxpair (1, ones (2,2)) %!error <invalid dimension DIM> cplxpair (1, [], 3) +