unit dmath;

interface

const
  GOLDEN_RATION = 1.6180339887;
  EPS: Double = 10e-6;

function Min(A, B: Integer): Integer;
function Max(A, B: Integer): Integer;
function Minf(A, B: Single): Single;
function Maxf(A, B: Single): Single;
function Mind(A, B: Double): Double;
function Maxd(A, B: Double): Double;

function Ternar(C: Boolean; A, B: Integer): Integer; inline; overload;
function Ternar(C: Boolean; A, B: Single): Single; inline; overload;
function Ternar(C: Boolean; A, B: PAnsiChar): PAnsiChar; inline; overload;
function Ternar(C: Pointer; A, B: Integer): Integer; inline; overload;
function Ternar(C: Pointer; A, B: PAnsiChar): PAnsiChar; inline; overload;

// Linear interpolation
function Lerp(A, B, F: Single): Single; overload;
function Lerp(A, B, F: Double): Double; overload;

// Trigonometry
function Tan(X: Single): Single;
function ArcTan2(Y, X: Single): Single;
function ArcCos(X: Single): Single;

// Bits
function IsPOT(I: LongInt): Boolean;

function SignF(X: Single): LongInt;
function SignD(X: Double): LongInt;

function DivMod(Dividend, Divisor: Cardinal; out Remainder: Cardinal): Cardinal;

implementation

function Min(A, B: Integer): Integer;
begin
  if A < B then
    Result := A
  else
    Result := B;
end;

function Max(A, B: Integer): Integer;
begin
  if A < B then begin
    Result := B;
  end else
    Result := A;
end;

function Minf(A, B: Single): Single;
begin
  if A < B then begin
    Result := A;
  end else
    Result := B;
end;

function Maxf(A, B: Single): Single;
begin
  if A < B then begin
    Result := B;
  end else
    Result := A;
end;

function Mind(A, B: Double): Double;
begin
  if A < B then begin
    Result := A;
  end else
    Result := B;
end;

function Maxd(A, B: Double): Double;
begin
  if A < B then begin
    Result := B;
  end else
    Result := A;
end;

function Ternar(C: Boolean; A, B: Integer): Integer;
begin
  if C then
    Result := A
  else
    Result := B;	
end;

function Ternar(C: Boolean; A, B: Single): Single;
begin
  if C then
    Result := A
  else
    Result := B;	
end;

function Ternar(C: Boolean; A, B: PAnsiChar): PAnsiChar;
begin
  if C then
    Result := A
  else
    Result := B;	
end;

function Ternar(C: Pointer; A, B: Integer): Integer;
begin
  if C = nil then
    Result := B
  else
    Result := A;	
end;

function Ternar(C: Pointer; A, B: PAnsiChar): PAnsiChar;
begin
  if C = nil then
    Result := B
  else
    Result := A;	
end;

function Lerp(A, B, F: Single): Single;
begin
  Result := A + (B - A) * F;
end;

function Lerp(A, B, F: Double): Double;
begin
  Result := A + (B - A) * F;
end;

// TODO i386 optimization
function ArcTan2(Y, X: Single): Single;
begin
  if X = 0 then begin
    if Y = 0 then begin
      Exit(0.0);
    end else if Y > 0 then begin
      Exit(pi / 2);
    end else
      Exit(- pi / 2);
  end;
  Result := ArcTan(Y / X);
  if X < 0.0 then
    Result := Result + pi;
  if Result > pi then
    Result := Result - 2 * pi;
end;

function Tan(X: Single): Single;
begin
  Result := Sin(X) / Cos(X);
end;

function ArcCos(X: Single): Single;
begin
  if Abs(X) = 1.0 then begin
    if X < 0.0 then begin
      Result := Pi;
	end else
      Result := 0;
  end else
    Result := ArcTan2(Sqrt((1.0 - X) * (1.0 + X)), X);
end;

function IsPOT(I: LongInt): Boolean;
begin
  Result := ((I - 1) and I) = 0;
end;

function SignF(X: Single): LongInt;
begin
  if X > 0 then begin
    Exit(1);
  end else if X < 0 then begin
    Exit(-1);
  end else
    Exit(0);
end;

function SignD(X: Double): LongInt;
begin
  if X > 0 then begin
    Exit(1);
  end else if X < 0 then begin
    Exit(-1);
  end else
    Exit(0);
end;

function DivMod(Dividend, Divisor: Cardinal; out Remainder: Cardinal): Cardinal;
begin
  // Compute div
  Result := Dividend div Divisor;
  // Compute mod
  Remainder := Dividend - (Result * Divisor);
end;

end.
