function [ arg, status ] = zero_rc ( a, b, t, value, status )

%*****************************************************************************80
%
%% zero_rc() seeks a root of a function F(X) using reverse communication.
%
%  Discussion:
%
%    The interval [A,B] must be a change of sign interval for F.
%    That is, F(A) and F(B) must be of opposite signs.  Then
%    assuming that F is continuous implies the existence of at least
%    one value C between A and B for which F(C) = 0.
%
%    The location of the zero is determined to within an accuracy
%    of 4 * EPSILON * abs ( C ) + 2 * T.
%
%    The routine is a revised version of the Brent zero finder
%    algorithm, using reverse communication.
%
%    Thanks to Thomas Secretin for pointing out a transcription error in the
%    setting of the value of P, 11 February 2013.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    13 July 2021
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Richard Brent,
%    Algorithms for Minimization Without Derivatives,
%    Dover, 2002,
%    ISBN: 0-486-41998-3,
%    LC: QA402.5.B74.
%
%  Input:
%
%    real A, B, the endpoints of the change of sign interval.
%
%    real T, a positive error tolerance.
%
%    real VALUE, the function value at ARG, as requested
%    by the routine on the previous call.
%
%    integer STATUS, used to communicate between the user and the routine.  
%    The user only sets STATUS to zero on the first call, to indicate that this 
%    is a startup call.  Thereafter, the input value should be the output value
%    from the previous call.
%
%  Output:
%
%    real ARG, the currently considered point.  The user
%    does not need to initialize this value.  On return with STATUS positive,
%    the user is requested to evaluate the function at ARG, and return
%    the value in VALUE.  On return with STATUS zero, ARG is the routine's
%    estimate for the function's zero.
%
%    integer STATUS.  The routine returns STATUS
%    positive to request that the function be evaluated at ARG, or returns
%    STATUS as 0, to indicate that the iteration is complete and that
%    ARG is the estimated zero
%
  persistent c;
  persistent d;
  persistent e;
  persistent fa;
  persistent fb;
  persistent fc;
  persistent sa;
  persistent sb;
%
%  Input STATUS = 0.
%  Initialize, request F(A).
%
  if ( status == 0 )

    sa = a;
    sb = b;
    e = sb - sa;
    d = e;

    status = 1;
    arg = a;
    return
%
%  Input STATUS = 1.
%  Receive F(A), request F(B).
%
  elseif ( status == 1 )

    fa = value;

    status = 2;
    arg = sb;
    return
%
%  Input STATUS = 2
%  Receive F(B).
%
  elseif ( status == 2 )

    fb = value;

    if ( 0.0 < fa * fb )
      status = -1;
      return
    end

    c = sa;
    fc = fa;

  else

    fb = value;

    if ( ( 0.0 < fb && 0.0 < fc ) || ( fb <= 0.0 && fc <= 0.0 ) )
      c = sa;
      fc = fa;
      e = sb - sa;
      d = e;
    end

  end
%
%  Compute the next point at which a function value is requested.
%
  if ( abs ( fc ) < abs ( fb ) )

    sa = sb;
    sb = c;
    c = sa;
    fa = fb;
    fb = fc;
    fc = fa;

  end

  tol = 2.0 * eps * abs ( sb ) + t;
  m = 0.5 * ( c - sb );

  if ( abs ( m ) <= tol || fb == 0.0 )
    status = 0;
    arg = sb;
    return
  end

  if ( abs ( e ) < tol || abs ( fa ) <= abs ( fb ) )

    e = m;
    d = e;

  else

    s = fb / fa;

    if ( sa == c )

      p = 2.0 * m * s;
      q = 1.0 - s;

    else

      q = fa / fc;
      r = fb / fc;
      p = s * ( 2.0 * m * q * ( q - r ) - ( sb - sa ) * ( r - 1.0 ) );
      q = ( q - 1.0 ) * ( r - 1.0 ) * ( s - 1.0 );

    end

    if ( 0.0 < p )
      q = - q;
    else
      p = - p;
    end

    s = e;
    e = d;

    if ( 2.0 * p < 3.0 * m * q - abs ( tol * q ) && p < abs ( 0.5 * s * q ) )
      d = p / q;
    else
      e = m;
      d = e;
    end

  end

  sa = sb;
  fa = fb;

  if ( tol < abs ( d ) )
    sb = sb + d;
  elseif ( 0.0 < m )
    sb = sb + tol;
  else
    sb = sb - tol;
  end

  arg = sb;
  status = status + 1;

  return
end

