unit DerivLib;

{*******************************************************
 * knihovna pro priblizny vypocet prvni derivace       *
 * a zjisteni znamenka druhe derivace                  *
 *                                                     *
 * Vytvoril: Adam Husar, xhusar01@stud.fit.vutbr.cz    *
 * Datum posledni upravy: 9. 4. 2003                   *
 *******************************************************}

interface

uses
  FEvalLib;

type
  TDerive = class
    public
      constructor Create(Accuracy: extended);
      destructor  Close;

      function    CountFirst(Func: TFunctionEval; Value: extended): extended;
      function    GetSecondSign(Func: TFunctionEval; Value: extended;
                      Direction: integer): integer;

      procedure   SetAccuracy(Accuracy: extended);
      function    GetAccuracy: extended;
    private
      Acc: extended; {urcuje pribliznou presnost s jakou se bude
                      pocitat 1. derivace}
  end;

const
  DER_FIRST_ACCDIV = 100;
  DER_SEC_ACCMUL   = 10;
  DER_SEC_ACCDIV   = 1000000;

implementation
uses
  Math;

constructor TDerive.Create(Accuracy: extended);
begin
  Acc:= Accuracy;
end;

destructor TDerive.Close;
begin
end;

procedure TDerive.SetAccuracy(Accuracy: extended);
begin
  Acc:= Accuracy;
end;

function  TDerive.GetAccuracy: extended;
begin
  GetAccuracy:= Acc;
end;


function TDerive.CountFirst(Func: TFunctionEval; Value: extended): extended;
 {funkce vraci pribliznou hodnotu prvni derivace}
var
  h, extRes: extended;
begin
  if (Acc <> 0) and (Func.GetLoadedExpr <> '') then begin
    h:= Acc / DER_FIRST_ACCDIV;

   {"limitni" vypocet derivace}
    extRes:= ( Func.EvalExpr(Value + h) - Func.EvalExpr(Value)) / h;
  end
  else
    extRes:= 0;

  CountFirst:= extRes;
end;


function TDerive.GetSecondSign(Func: TFunctionEval; Value: extended;
    Direction: integer): integer;
{fce vraci znamenko druhe derivace (-1, 0, +1),
 kontroluje se, zda funkcni hodnota tecny fce je vetsi nebo mensi v bode
 vzdalenem o 10-nasobek presnosti ve smeru Direction (kladnem nebo zapornem)
 je > nebo < nez fci hodnota zkoumane fce}
var
  k, q, Point, yt, yf: extended;
  iRes: integer;

begin
  if (Acc <> 0) and (Func.GetLoadedExpr <> '') and (Direction <> 0) then begin
   {vypocet tecny - y = k*x + q }
    k:= CountFirst(Func, Value); {smernice tecny}
    q:= Func.EvalExpr(Value);    {posun na y-ove ose}

    Point:= Value + Acc * DER_SEC_ACCMUL * Sign(Direction);  {kontrolni bod}

    yt:= k*(Point - Value) + q;  {fcni hodn. tecny v bode}
    yf:= Func.EvalExpr(Point);

    if abs(yt - yf) <= Acc/DER_SEC_ACCDIV then
      iRes:= 0
    else if yf > yt then
      iRes:= +1
    else 
      iRes:= -1;
  end
  else
    iRes:= 0;

  GetSecondSign:= iRes;
end;

end.
