changeset 24913:9da779d2f029 stable

cosint improve signed zero imag input near branch cut Stop special casing the origin, instead have log deal with signed zeros (real and complex). Ensure we approach the branch cut (negative real axis) correctly based on signed 0 for imaginary part. cosint.m: handle complex signed zero, add and modify BIST.
author Colin Macdonald <cbm@m.fsf.org>
date Tue, 23 Jan 2018 23:14:50 -0800
parents 08c871c4147b
children d7293106945c
files scripts/specfun/cosint.m
diffstat 1 files changed, 38 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/specfun/cosint.m	Tue Jan 23 22:43:03 2018 -0800
+++ b/scripts/specfun/cosint.m	Tue Jan 23 23:14:50 2018 -0800
@@ -77,18 +77,25 @@
   endif
 
   sz = size (x);
-  x = x(:);
+  #x = reshape (x, numel (x), 1);
+  if (iscomplex (x))
+    ## workaround reshape narrowing to real (#52953)
+    x = complex (real (x)(:), imag (x)(:));
+  else
+    x = x(:);
+  end
+
   y = zeros (size (x), class (x));
   tol = eps (class (x));
 
   i_miss = true (length (x), 1);
 
   ## special values
-  y(x == 0) = - Inf;
   y(x == Inf) = 0;
-  y(x == - Inf) = 1i * pi;
+  y((x == -Inf) & !signbit (imag(x))) = 1i * pi;
+  y((x == -Inf) &  signbit (imag(x))) = -1i * pi;
 
-  i_miss = ((i_miss) & (x != 0) & (x != Inf) & (x != - Inf));
+  i_miss = ((i_miss) & (x != Inf) & (x != -Inf));
 
   ## For values large in modulus and not in (-oo,0), we use the relation
   ## with expint
@@ -108,10 +115,16 @@
 
   ## For values small in modulus, use the series expansion (also near (-oo, 0])
   i_miss = ((i_miss) & (!flag_large));
-  xx = x(i_miss);
+  if (iscomplex (x))
+    ## indexing can lose imag part: if it was -0, we could end up on the
+    ## wrong right side of the branch cut along the negative real axis.
+    xx = complex (real (x)(i_miss), imag (x)(i_miss));
+  else
+    xx = x(i_miss);
+  end
   ssum = - xx .^ 2 / 4; # First term of the series expansion
   gma = 0.57721566490153286060651209008; # Euler gamma constant
-  yy = gma + log (xx) + ssum;
+  yy = gma + log (complex (xx)) + ssum; # log(complex(...) handles signed zero
   flag_sum = true (nnz (i_miss), 1);
   it = 1;
   maxit = 300;
@@ -139,8 +152,12 @@
 %! assert (A, B, -5e-15);
 
 %!assert (cosint (0), - Inf)
+%!assert (cosint (-0), -inf + 1i*pi)
+%!assert (cosint (complex (-0, 0)), -inf + 1i*pi)
+%!assert (cosint (complex (-0, -0)), -inf - 1i*pi)
 %!assert (cosint (inf), 0)
 %!assert (cosint (-inf), 1i * pi)
+%!assert (cosint (complex (-inf, -0)), -1i * pi)
 %!assert (isnan (cosint (nan)))
 
 %!assert (class (cosint (single (1))), "single")
@@ -164,12 +181,19 @@
 %! assert (cosint(x), y_ex, -3e-15);
 
 %!test
-%! x = -(0:4) ';
-%! y_ex = [-Inf
-%!         0.337403922900968135 + 3.14159265358979324*I
-%!         0.422980828774864996 + 3.14159265358979324*I
-%!         0.119629786008000328 + 3.14159265358979324*I
-%!         -0.140981697886930412 + 3.14159265358979324*I];
+%! x = -(1:4).';
+%! y_ex = [0.337403922900968135 + pi*1i
+%!         0.422980828774864996 + pi*1i
+%!         0.119629786008000328 + pi*1i
+%!         -0.140981697886930412 + pi*1i];
+%! assert (cosint (x), y_ex, -4*eps);
+
+%!test
+%! x = complex (-(1:4).', -0);
+%! y_ex = [0.337403922900968135 - pi*1i
+%!         0.422980828774864996 - pi*1i
+%!         0.119629786008000328 - pi*1i
+%!         -0.140981697886930412 - pi*1i];
 %! assert (cosint (x), y_ex, -4*eps);
 
 %!test
@@ -182,9 +206,8 @@
 %! assert (cosint (x), y_ex, -4*eps);
 
 %!test
-%! x = - 1i * (0:4).';
-%! y_ex = [- Inf
-%!         0.837866940980208241 - 1.57079632679489662*I
+%! x = -1i * (1:4).';
+%! y_ex = [0.837866940980208241 - 1.57079632679489662*I
 %!         2.45266692264691452 - 1.57079632679489662*I
 %!         4.96039209476560976 - 1.57079632679489662*I
 %!         9.81354755882318556 - 1.57079632679489662*I];