function value = r8_psi ( x )

%*****************************************************************************80
%
%% R8_PSI evaluates the psi function of an R8 argument.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    25 September 2011
%
%  Author:
%
%    Original FORTRAN77 version by Wayne Fullerton.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Wayne Fullerton,
%    Portable Special Function Routines,
%    in Portability of Numerical Software,
%    edited by Wayne Cowell,
%    Lecture Notes in Computer Science, Volume 57,
%    Springer 1977,
%    ISBN: 978-3-540-08446-4,
%    LC: QA297.W65.
%
%  Input:
%
%    real X, the argument.
%
%  Output:
%
%    real VALUE, the psi function of X.
%
  persistent apsics
  persistent dxrel
  persistent ntapsi
  persistent ntpsi
  persistent psics
  persistent xbig

  if ( isempty ( ntpsi ) )

    apsics = [ ...
      -0.832710791069290760174456932269E-03, ...
      -0.416251842192739352821627121990E-03, ...
      +0.103431560978741291174463193961E-06, ...
      -0.121468184135904152987299556365E-09, ...
      +0.311369431998356155521240278178E-12, ...
      -0.136461337193177041776516100945E-14, ...
      +0.902051751315416565130837974000E-17, ...
      -0.831542997421591464829933635466E-19, ...
      +0.101224257073907254188479482666E-20, ...
      -0.156270249435622507620478933333E-22, ...
      +0.296542716808903896133226666666E-24, ...
      -0.674686886765702163741866666666E-26, ...
      +0.180345311697189904213333333333E-27, ...
      -0.556901618245983607466666666666E-29, ...
      +0.195867922607736251733333333333E-30, ...
      -0.775195892523335680000000000000E-32 ]';
    psics = [ ...
      -0.38057080835217921520437677667039E-01, ...
      +0.49141539302938712748204699654277, ...
      -0.56815747821244730242892064734081E-01, ...
      +0.83578212259143131362775650747862E-02, ...
      -0.13332328579943425998079274172393E-02, ...
      +0.22031328706930824892872397979521E-03, ...
      -0.37040238178456883592889086949229E-04, ...
      +0.62837936548549898933651418717690E-05, ...
      -0.10712639085061849855283541747074E-05, ...
      +0.18312839465484165805731589810378E-06, ...
      -0.31353509361808509869005779796885E-07, ...
      +0.53728087762007766260471919143615E-08, ...
      -0.92116814159784275717880632624730E-09, ...
      +0.15798126521481822782252884032823E-09, ...
      -0.27098646132380443065440589409707E-10, ...
      +0.46487228599096834872947319529549E-11, ...
      -0.79752725638303689726504797772737E-12, ...
      +0.13682723857476992249251053892838E-12, ...
      -0.23475156060658972717320677980719E-13, ...
      +0.40276307155603541107907925006281E-14, ...
      -0.69102518531179037846547422974771E-15, ...
      +0.11856047138863349552929139525768E-15, ...
      -0.20341689616261559308154210484223E-16, ...
      +0.34900749686463043850374232932351E-17, ...
      -0.59880146934976711003011081393493E-18, ...
      +0.10273801628080588258398005712213E-18, ...
      -0.17627049424561071368359260105386E-19, ...
      +0.30243228018156920457454035490133E-20, ...
      -0.51889168302092313774286088874666E-21, ...
      +0.89027730345845713905005887487999E-22, ...
      -0.15274742899426728392894971904000E-22, ...
      +0.26207314798962083136358318079999E-23, ...
      -0.44964642738220696772598388053333E-24, ...
      +0.77147129596345107028919364266666E-25, ...
      -0.13236354761887702968102638933333E-25, ...
      +0.22709994362408300091277311999999E-26, ...
      -0.38964190215374115954491391999999E-27, ...
      +0.66851981388855302310679893333333E-28, ...
      -0.11469986654920864872529919999999E-28, ...
      +0.19679385886541405920515413333333E-29, ...
      -0.33764488189750979801907200000000E-30, ...
      +0.57930703193214159246677333333333E-31 ]';

    ntpsi = r8_inits ( psics, 42, 0.1 * r8_mach ( 3 ) );
    ntapsi = r8_inits ( apsics, 16, 0.1 * r8_mach ( 3 ) );
    xbig = 1.0 / sqrt ( r8_mach ( 3 ) );
    dxrel = sqrt ( r8_mach ( 4 ) );

  end

  y = abs ( x );

  if ( y < 10.0 )

    n = r8_aint ( x );
    if ( x < 0.0 )
      n = n - 1;
    end
    y = x - n;
    n = n - 1;
    value = r8_csevl ( 2.0 * y - 1.0, psics, ntpsi );

    if ( n == 0 )

      return

    elseif ( n < 0 )

      n = - n;

      if ( x == 0.0 )
        fprintf ( 1, '\n' );
        fprintf ( 1, 'R8_PSI - Fatal error!\n' );
        fprintf ( 1, '  X is zero.\n' );
        error ( 'R8_PSI - Fatal error!' )
      end

      if ( x < 0.0 && x + n - 2 == 0.0 )
        fprintf ( 1, '\n' );
        fprintf ( 1, 'R8_PSI - Fatal error!\n' );
        fprintf ( 1, '  X is a negative integer.\n' );
        error ( 'R8_PSI - Fatal error!' )
      end

      if ( x < - 0.5 && ...
        abs ( ( x - r8_aint ( x - 0.5 ) ) / x ) < dxrel )
        fprintf ( 1, '\n' );
        fprintf ( 1, 'R8_PSI - Warning!\n' );
        fprintf ( 1, '  Answer is less than half precision\n' );
        fprintf ( 1, '  because X is near a negative integer.\n' );
      end

      for i = 1 : n
        value = value - 1.0 / ( x + i - 1 );
      end

    elseif ( 0 < n )

      for i = 1 : n
        value = value + 1.0 / ( y + i );
      end

    end

  else

    if ( y < xbig )
      aux = r8_csevl ( 8.0 / y / y - 1.0, apsics, ntapsi );
    else
      aux = 0.0;
    end

    if ( x < 0.0 )

      value = log ( abs ( x ) ) - 0.5 / x + aux - pi * r8_cot ( pi * x );

    elseif ( 0.0 < x )

      value = log ( x ) - 0.5 / x + aux;

    end

  end

  return
end
