unit add_math;

interface

function Power_(x, y: Extended): Extended; // x^y
function SQRT_(x:Extended):Extended;
function LN_(x:Extended):Extended;
function DIVISION_(x,y:Extended):Extended;
function LogN_(Base, X: Extended): Extended;
function tg(X: Extended): Extended;
function ctg(X: Extended): Extended;
function arctg(X: Extended): Extended;
function arcsin_(X: Extended): Extended;
function arccos_(X: Extended): Extended;
function lg(X: Extended): Extended;

implementation
  uses SysUtils,Math;
  
const zero=1e-30;

function IntPower(Base: Extended; Exponent: Integer): Extended;
asm
        mov     ecx, eax
        cdq
        fld1                      { Result := 1 }
        xor     eax, edx
        sub     eax, edx          { eax := Abs(Exponent) }
        jz      @@3
        fld     Base
        jmp     @@2
@@1:    fmul    ST, ST            { X := Base * Base }
@@2:    shr     eax,1
        jnc     @@1
        fmul    ST(1),ST          { Result := Result * X }
        jnz     @@1
        fstp    st                { pop X from FPU stack }
        cmp     ecx, 0
        jge     @@3
        fld1
        fdivrp                    { Result := 1 / Result }
@@3:
        fwait
end;

function Power_(x, y: Extended): Extended; // x^y
begin
  if y = 0.0 then
    Result := 1.0               { n^0 = 1 }
  else if (x = 0.0) and (y > 0.0) then
    Result := 0.0               { 0^n = 0, n > 0 }
  else if (Frac(y) = 0.0) and (Abs(y) <= MaxInt) then
    Result := IntPower(x, Integer(Trunc(y)))
  else if x>0 then
    Result := Exp(y * Ln(x))
  else raise Exception.create('NotInODZ');
end;

function SQRT_(x:Extended):Extended;
begin
  if x>=zero then Result:=sqrt(x)
  else raise Exception.create('NotInODZ');
end;

function LN_(x:Extended):Extended;
begin
  if x>=zero then Result:=ln(x)
  else raise Exception.create('NotInODZ');
end;

function DIVISION_(x,y:Extended):Extended;
begin
  if abs(y)>=zero then Result:=x/y
  else raise Exception.create('NotInODZ');
end;

function LogN(Base, X: Extended): Extended;
{ Log.N(X) := Log.2(X) / Log.2(N) }
asm
        FLD1
        FLD     X
        FYL2X
        FLD1
        FLD     Base
        FYL2X
        FDIV
        FWAIT
end;

function LogN_(Base, X: Extended): Extended;
begin
  if (x>=zero)and(base>0)and(base<>1) then Result:=LogN(Base,x)
  else raise Exception.create('NotInODZ');
end;

function tg(x:Extended):Extended;
  var s,c:real;
begin
  s:=sin(x); c:=cos(x);
  if abs(c)>=zero then Result:=s/c
  else raise Exception.create('NotInODZ');
end;

function ctg(x:Extended):Extended;
  var s,c:real;
begin
  s:=sin(x); c:=cos(x);
  if abs(s)>=zero then Result:=c/s
  else raise Exception.create('NotInODZ');
end;

function arctg(x:Extended):Extended;
begin
  Result:=arctan(x);
end;

function arcsin_(x:Extended):Extended;
begin
  if (x>=-1)and(x<=1) then Result:=arcsin(x)
  else raise Exception.create('NotInODZ');
end;

function arccos_(x:Extended):Extended;
begin
  if (x>=-1)and(x<=1) then Result:=arccos(x)
  else raise Exception.create('NotInODZ');
end;

function lg(x:Extended):Extended;
begin
  Result:=ln_(x)/ln_(10);
end;

end.
