view scripts/specfun/sinint.m @ 24911:8d6f3941a118 stable

Support single precision in sinint/cosint. sinint.m: support single precision. cosint.m: support single precision.
author Colin Macdonald <cbm@m.fsf.org>
date Tue, 23 Jan 2018 20:17:25 -0800
parents b98755ef7572
children 08c871c4147b
line wrap: on
line source

## Copyright (C) 2017 Michele Ginesi
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## Author: Michele Ginesi <michele.ginesi@gmail.com>

## -*- texinfo -*-
## @deftypefn {} {} sinint (@var{x})
## Compute the sine integral function:
## @tex
## $$
## {\rm Si} (x) = \int_0^x {\sin (t) \over t} dt
## $$
## @end tex
## @ifnottex
##
## @example
## @group
##            x
##           /
## Si (x) =  | sin (t) / t dt
##           /
##          0
## @end group
## @end example
## @end ifnottex
##
## Reference:
##
## @nospell{M. Abramowitz and I.A. Stegun},
## @cite{Handbook of Mathematical Functions}
## 1964.
##
## @seealso{cosint, expint, sin}
##
## @end deftypefn

function [y] = sinint (x)

  if (nargin != 1)
    print_usage ();
  endif

  sz = size (x);
  x = x(:);
  y = zeros (size (x), class (x));
  tol = eps (class (x));

  i_miss = true (length (x), 1);

  ## Trivial values
  y(x == 0) = 0;
  y(x == Inf) = pi / 2;
  y(x == - Inf) = - pi / 2;

  i_miss = ((i_miss) & (x != 0) & (x != Inf) & (x != - Inf));

  ## For values large in modulus we use the relation with expint

  flag_large = abs (x) > 2;
  xx = x(flag_large & i_miss);
  ii_neg = (real (xx) < 0);
  xx(ii_neg) *= -1;
  ii_conj = ((real (xx) == 0) & (imag (xx) < 0));
  xx(ii_conj) = conj (xx(ii_conj));
  yy = -0.5i * (expint (1i * xx) - expint (-1i * xx)) + pi / 2;
  yy(ii_neg) *= -1;
  yy(ii_conj) = conj (yy(ii_conj));
  y(i_miss & flag_large) = yy;

  ## For values small in modulus we use the series expansion

  i_miss = ((i_miss) & (!flag_large));
  xx = x(i_miss);
  ssum = xx; # First term of the series expansion
  yy = ssum;
  flag_sum = true (nnz (i_miss), 1);
  it = 0;
  maxit = 300;
  while ((any (flag_sum)) && (it < maxit));
    ssum .*= - xx .^ 2 * (2 * it + 1) / ((2 * it + 3) ^ 2 * (2 * it + 2));
    yy(flag_sum) += ssum (flag_sum);
    flag_sum = (abs (ssum) >= tol);
    it++;
  endwhile

  y(i_miss) = yy;

  y = reshape (y, sz);

endfunction


%!test
%! x = 1.1;
%! %y = sym(11)/10;
%! A = sinint (x);
%! %B = double (sinint (y));
%! B = 1.02868521867373;
%! assert (A, B, -5e-15);

%!test
%! %y = [2 3 sym(pi); exp(sym(1)) 5 6];
%! x = [2, 3, pi; exp(1), 5, 6];
%! A = sinint (x);
%! %B = double (sinint (y));
%! B = [1.60541297680269, 1.84865252799947, 1.85193705198247e+00; ...
%!      1.82104026914757, 1.54993124494467, 1.42468755128051e+00];
%! assert (A, B, -5e-15);

%!assert (sinint (0), 0)
%!assert (sinint (inf), pi/2)
%!assert (sinint (-inf), -pi/2)
%!assert (isnan (sinint (nan)))

%!assert (class (sinint (single (1))), "single")

##tests against maple
%!assert (sinint (1), 0.9460830703671830149414, -2*eps)
%!assert (sinint (-1), -0.9460830703671830149414, -2*eps)
%!assert (sinint (pi), 1.851937051982466170361, -2*eps)
%!assert (sinint (-pi), -1.851937051982466170361, -2*eps)
%!assert (sinint (300), 1.5708810882137495193, -2*eps)
%!assert (sinint (1e4), 1.5708915453859619157, -2*eps)
%!assert (sinint (20i), 1.2807826332028294459e7*1i, -2*eps)

%!test
%! x = (0:4)';
%! y_ex = [0
%!         0.946083070367183015
%!         1.60541297680269485
%!         1.84865252799946826
%!         1.75820313894905306];
%! assert (sinint (x), y_ex, -4*eps);

%!test
%! x = -(0:4)';
%! y_ex = - [0
%!           0.946083070367183015
%!           1.60541297680269485
%!           1.84865252799946826
%!           1.75820313894905306];
%! assert (sinint (x), y_ex, -4*eps);

%!test
%! x = 1i * (0:4).';
%! y_ex = [0
%!         1.05725087537572851*I
%!         2.50156743335497564*I
%!         4.97344047585980680*I
%!         9.81732691123303446*I];
%! assert (sinint (x), y_ex, -4*eps);

%!test
%! x = - 1i * (0:4).';
%! y_ex = - [0
%!           1.05725087537572851*I
%!           2.50156743335497564*I
%!           4.97344047585980680*I
%!           9.81732691123303446*I];
%! assert (sinint (x), y_ex, -4*eps);

%!test
%! % maple:
%! % > A := [1+2*I, -2 + 5*I, 100, 10*I, -1e-4 + 1e-6*I, -20 + I];
%! % > for a in A do evalf(Si(a)) end do;
%! x = [1+2i; -2+5i; 100; 10i; -1e-4 + 1e-6*1i; -20-1i];
%! A = [ 1.6782404878293681180 + 2.0396845546022061045*1i
%!      -18.154174221650281533 + 1.6146414539230479060*1i
%!       1.5622254668890562934
%!       1246.1144901994233444*1i
%!      -0.000099999999944461111128 + 0.99999999833338888972e-6*1i
%!      -1.5386156269726011209 - 0.053969388020443786229*1i ];
%! B = sinint (x);
%! assert (A, B, -3*eps)
%! B = sinint (single (x));
%! assert (A, B, -3*eps ("single"))