with Ada.Text_IO, Ada.Finalization, Rounding, Scalars, Globals, Logicals, Rationals, Flts;
use Ada.Text_IO, Ada.Finalization, Rounding, Scalars, Globals, Logicals, Rationals, Flts;

pragma Elaborate_All (Ada.Text_IO,Ada.Finalization,Rounding,Scalars,Globals,Logicals,Rationals,Flts);

package MPFR.Floats is

  pragma Elaborate_Body;

  type MPFloat is new Controlled with private;

  overriding procedure Initialize(S: in out MPFloat);
  overriding procedure Adjust(S: in out MPFloat);
  overriding procedure Finalize(S: in out MPFloat);

  --- auxiliary
  procedure NOP(Dummy: in out MPFloat);
  procedure NOP(Dummy1: in Flt; Dummy2: in out MPFloat);
  function ReturnTrue(Dummy: MPFloat) return Boolean;
  function IsZero(S: MPFloat) return Boolean;
  procedure SetZero(S: in out MPFloat);
  procedure SetZero(Dummy: in Flt; S: in out MPFloat);
  procedure SetZero(Dummy: in MPFloat; S: in out MPFloat);
  function ReturnZero(Dummy: MPFloat) return Flt;
  function ReturnZero(Dummy: Flt) return MPFloat;
  function ReturnZero(Dummy: MPFloat) return MPFloat;
  procedure Copy(S1: in MPFloat; S2: in out MPFloat);
  function Copy(S: MPFloat) return MPFloat;
  function Approx(S: MPFloat) return Flt;                   --- approx
  function FirstArg(Q: Rational; Dummy: Flt) return MPFloat;
  function FirstArg(S: MPFloat; Dummy: Flt) return MPFloat;
  procedure Between(S1,S2: in Flt; S3: in out MPFloat);     --- approx middle
  function Between(S1,S2: Flt) return MPFloat;              --- approx middle
  procedure Between(S1: in MPFloat; S2: in out MPFloat);    --- approx middle
  function Between(S1,S2: MPFloat) return MPFloat;          --- approx middle

  --- basic
  function Info(Dummy: MPFloat) return Scalar_Info;
  procedure Details(S: MPFloat);
  function IsSharp(S: MPFloat) return Boolean renames ReturnTrue;
  function IsNumbers(S: MPFloat) return Boolean renames ReturnTrue;
  procedure SetSmallZero(S: in out MPFloat);
  procedure Swap(S1,S2: in out MPFloat);

  --- sets
  function Center0(S: MPFloat) return Boolean renames IsZero;
  function Contains0(S: MPFloat) return Logical;
  function Contains(S1,S2: MPFloat) return Logical;
  procedure BallAt0(R: in Flt; S: in out MPFloat) renames SetZero;
  function BallAt0(R: Flt) return MPFloat renames ReturnZero;
  procedure DiskAt0(R: in Flt; S: in out MPFloat) renames SetZero;
  function DiskAt0(R: Flt) return MPFloat renames ReturnZero;
  procedure ToErr(S: in out MPFloat) renames SetZero;
  procedure ToErr(S1: in MPFloat; S2: in out MPFloat) renames SetZero;
  function ToErr(S: MPFloat) return MPFloat renames ReturnZero;
  procedure Center(S: in out MPFloat) renames NOP;
  procedure Center(S1: in MPFloat; S2: in out MPFloat) renames Copy;
  function Center(S: MPFloat) return MPFloat renames Copy;
  procedure CenterDisk(S: in out MPFloat) renames NOP;
  procedure CenterDisk(S1: in MPFloat; S2: in out MPFloat) renames Copy;
  function CenterDisk(S: MPFloat) return MPFloat renames Copy;
  procedure ModCenter(S: in out MPFloat) renames SetZero;
  procedure ModCenter(S1: in MPFloat; S2: in out MPFloat) renames SetZero;
  function ModCenter(S: MPFloat) return MPFloat renames ReturnZero;
  procedure ModNumbers(S: in out MPFloat) renames SetZero;
  procedure ModNumbers(S1: in MPFloat; S2: in out MPFloat) renames SetZero;
  function ModNumbers(S: MPFloat) return MPFloat renames ReturnZero;
  procedure ErrMult(R: in Radius; S: in out MPFloat) renames NOP;
  procedure Union(S1: in MPFloat; S2: in out MPFloat) renames Between;
  function Union(S1,S2: MPFloat) return MPFloat renames Between;                  -- approx middle
  procedure Intersection(S1: in MPFloat; S2: in out MPFloat; Empty: out Logical); -- approx middle

  --- order
  function Sign(S: MPFloat) return Integer;
  function Compare(R: Flt; S: MPFloat) return Integer;
  function Compare(S1,S2: MPFloat) return Integer;
  function "<"(S1,S2: MPFloat) return Boolean;
  function "<="(S1,S2: MPFloat) return Boolean;
  function "="(S1,S2: MPFloat) return Boolean;
  function ">="(S1,S2: MPFloat) return Boolean;
  function ">"(S1,S2: MPFloat) return Boolean;
  procedure Min(S1: in MPFloat; S2: in out MPFloat);
  procedure Min(S1,S2: in MPFloat; S3: in out MPFloat);
  function Min(S1,S2: MPFloat) return MPFloat;
  procedure Max(S1: in MPFloat; S2: in out MPFloat);
  procedure Max(S1,S2: in MPFloat; S3: in out MPFloat);
  function Max(S1,S2: MPFloat) return MPFloat;
  function Sup(S: MPFloat) return Flt;
  function Inf(S: MPFloat) return Flt;

  --- arithmetic (most rounded)
  function "-"(S: MPFloat) return MPFloat;
  procedure Neg(S: in out MPFloat);
  procedure Neg(S1: in MPFloat; S2: in out MPFloat);
  procedure Add(I: in Integer; S: in out MPFloat);
  function "+"(S1,S2: MPFloat) return MPFloat;
  procedure Add(S1: in MPFloat; S2: in out MPFloat);
  procedure Sum(S1,S2: in MPFloat; S3: in out MPFloat);
  function "-"(S1,S2: MPFloat) return MPFloat;
  procedure Sub(S1: in MPFloat; S2: in out MPFloat);
  procedure Diff(S1,S2: in MPFloat; S3: in out MPFloat);
  function "*"(R: Flt; S: MPFloat) return MPFloat;
  procedure Mult(R: in Flt; S,Tmp: in out MPFloat);
  procedure Mult(R: in Flt; S: in out MPFloat);
  procedure Prod(R: in Flt; S1: in MPFloat; S2: in out MPFloat);
  procedure AddProd(R: in Flt; S1: in MPFloat; S2: in out MPFloat);
  procedure Mult(Q: in Rational; S: in out MPFloat);
  function "*"(S1,S2: MPFloat) return MPFloat;
  procedure Mult(S1: in MPFloat; S2: in out MPFloat);
  procedure Prod(S1,S2: in MPFloat; S3: in out MPFloat);
  procedure AddProd(R: in Flt; S1: in MPFloat; S2,Tmp: in out MPFloat);
  procedure AddProd(S1,S2: in MPFloat; S3,Tmp: in out MPFloat);
  procedure AddProd(S1,S2: in MPFloat; S3: in out MPFloat);
  procedure SumProd(S1,S2,S3: in MPFloat; S4: in out MPFloat);
  procedure SubProd(S1,S2: in MPFloat; S3,Tmp: in out MPFloat);
  procedure Div(R: in Flt; S,Tmp: in out MPFloat);
  procedure Div(R: in Flt; S: in out MPFloat);
  procedure Quot(S1: in MPFloat; R: in Flt; S2: in out MPFloat);
  function "/"(S: MPFloat; R: Flt) return MPFloat;
  procedure Div(S1: in MPFloat; S2: in out MPFloat);
  procedure Quot(S1,S2: in MPFloat; S3: in out MPFloat);
  function "/"(S1,S2: MPFloat) return MPFloat;
  procedure Inv(S1: in MPFloat; S2: in out MPFloat);
  function Inv(S: MPFloat) return MPFloat;
  function "**"(S: MPFloat; I: Integer) return MPFloat;

  --- fun (most rounded)
  function IsReal(S: MPFloat) return Boolean renames ReturnTrue;
  procedure Adjoint(S: in out MPFloat) renames NOP;
  procedure Adjoint(S1: in MPFloat; S2: in out MPFloat) renames Copy;
  function Adjoint(S: MPFloat) return MPFloat renames Copy;
  procedure Real_Part(S: in out MPFloat) renames NOP;
  function Real_Part(S: MPFloat) return MPFloat renames Copy;
  procedure Imag_Part(S: in out MPFloat) renames SetZero;
  function Imag_Part(S: MPFloat) return MPFloat renames ReturnZero;
  procedure Eval0(S: in out MPFloat) renames NOP;
  function "abs"(S: MPFloat) return MPFloat;
  procedure Norm(S: in out MPFloat);
  procedure Norm(S1: in MPFloat; S2: in out MPFloat);
  function Norm(S: MPFloat) return MPFloat renames "abs";
  function MaxNorm(S: MPFloat) return Radius;
  procedure Sqr(S: in out MPFloat);
  procedure Sqr(S1: in MPFloat; S2: in out MPFloat);
  function Sqr(S: MPFloat) return MPFloat;
  procedure Sqrt(S1: in MPFloat; S2: in out MPFloat);
  function Sqrt(S: MPFloat) return MPFloat;
  procedure Root(K: Positive; S1: in MPFloat; S2: in out MPFloat);
  function Root(K: Positive; S: MPFloat) return MPFloat;
  procedure Exp(S1: in MPFloat; S2: in out MPFloat);
  function Exp(S: MPFloat) return MPFloat;
  procedure Log(S1: in MPFloat; S2: in out MPFloat);
  function Log(S: MPFloat) return MPFloat;
  procedure ArcCos(S1: in MPFloat; S2: in out MPFloat);
  function ArcCos(S: MPFloat) return MPFloat;
  procedure ArcSin(S1: in MPFloat; S2: in out MPFloat);
  function ArcSin(S: MPFloat) return MPFloat;
  procedure Cos(S1: in MPFloat; S2: in out MPFloat);
  function Cos(S: MPFloat) return MPFloat;
  procedure Sin(S1: in MPFloat; S2: in out MPFloat);
  function Sin(S: MPFloat) return MPFloat;
  procedure Simple_Random(S: in out MPFloat);
  function Pi return MPFloat;
  procedure IPower(I: Integer; S1: in MPFloat; S2,Dummy: in out MPFloat);
  procedure QPower(Q: in Rational; S1: in MPFloat; S2: in out MPFloat);
  procedure Roots2(B,C: in MPFloat; U1,U2,V: in out MPFloat);
  procedure Roots3(B,C,D: in MPFloat; U0,U1,U2,V: in out MPFloat);

  --- conversion, io
  procedure Assign(I: in Integer; S: in out MPFloat);
  procedure Assign(Q: in Rational; S: in out MPFloat);
  procedure Assign(R: in Flt; S: in out MPFloat);
  function Scal(I: Integer) return MPFloat;
  function Scal(Q: Rational) return MPFloat;   --- rounded
  function Scal(R: Flt) return MPFloat;
  procedure Enclose(R1,R2: in Flt; S: in out MPFloat) renames Between; -- approx middle
  function Enclose(R1,R2: Flt) return MPFloat renames Between; -- approx middle
  function Val(S: MPFloat; R: Flt) return MPFloat renames FirstArg;
  function Image(S: MPFloat; Base: Positive; Digs: Natural := 0) return String;
  procedure Value(N: in String; Base: in Positive; R: in out MPFloat; Rounded: out Boolean);
  function Value(N: String; Base: Positive) return MPFloat; -- sets Just_Rounded
  procedure ValDec(N: in String; R: in out MPFloat); -- sets Just_Rounded
  function ValDec(N: String) return MPFloat; -- sets Just_Rounded
  procedure ValHex(N: in String; R: in out MPFloat; Rounded: out Boolean);
  function ValHex(N: String) return MPFloat; -- sets Just_Rounded
  function DecStr(S: MPFloat; Digs: Natural := 0) return String;
  function HexStr(S: MPFloat; Digs: Natural := 0) return String;
  procedure Show1(N: in String; S: in MPFloat; NewLine: in Boolean := True);
  procedure Show2(N: in String; S1,S2: in MPFloat; NewLine: in Boolean := True);
  procedure Put(F: in File_Type; S: in MPFloat; Decimal: in Boolean := False); -- includes New_Line
  procedure Get(F: in File_Type; S: in out MPFloat; Decimal: in Boolean := False);
  procedure Write(FileName: in String; S: in MPFloat; Decimal: in Boolean := False);
  procedure Read(FileName: in String; S: in out MPFloat; Decimal: in Boolean := False);

  subtype Rep is MPFloat;

  procedure Val(R: in LLFloat; S: in out Rep);
  function Val(R: LLFloat) return Rep;
  function Upper(S: Rep) return LLFloat;
  function Lower(S: Rep) return LLFloat;
  procedure PutStd(S: in MPFloat; C,R: out LLFloat);
  procedure PutStd(S: in MPFloat; C,R,B: out LLFloat);
  procedure GetStd(C,Dummy: in LLFloat; S: in out MPFloat);
  procedure GetStd(C,Dummy1,Dummy2: in LLFloat; S: in out MPFloat);
  procedure PutNum(S: in MPFloat; R: in out Rep) renames Copy;
  procedure GetNum(R: in Rep; S: in out MPFloat) renames Copy;

  --- misc
  function IsInteger(S: MPFloat) return Boolean;
  procedure Ceiling(S1: in MPFloat; S2: in out MPFloat); -- not rigorous
  function Ceiling(S1: MPFloat) return MPFloat;          -- not rigorous
  procedure Floor(S1: in MPFloat; S2: in out MPFloat);   -- not rigorous
  function Floor(S1: MPFloat) return MPFloat;            -- not rigorous
  procedure Round(S1: in MPFloat; S2: in out MPFloat);   -- not rigorous
  function Round(S1: MPFloat) return MPFloat;            -- not rigorous
  function Exponent(S: in MPFloat) return Integer;
  function Scaled(Eps: Flt) return Flt;
  function Epsilon(Eps: Flt) return Flt;
  procedure Set_Precision(Binary_Digits: in Positive);
  function Set_Precision(Binary_Digits: Positive) return Positive;
  procedure Set_Precision(Binary_Digits: in Positive; Dummy: in MPFloat);
  function Get_Precision(R: MPFloat) return Positive;
  procedure Set_Rounding_Mode(M: in Rounding_Mode);
  procedure Proper_Rounding;
  procedure Proper_Rounding(Dummy: in MPFloat);
  procedure Free_Cache(Dummy: in MPFloat);
  procedure Put_Numeric(N: in Positive; S: in Rep);     --- a primitive buffer
  procedure Get_Numeric(N: in Positive; S: in out Rep); --- a primitive buffer

  Scalar_IsNumeric: constant Boolean := True;
  Just_Rounded: Boolean := False;
  MPFR_Exception: exception;

private

  type MPFloat is new Controlled with
    record
      Val: MPFR_T;
    end record;

  procedure Reformat(P: in MP_Prec_T; V: in out MPFR_T);
  procedure Reformat(V: in out MPFR_T);
  procedure Fix_Precision(V: in out MPFR_T);
  function Num_Problem return Boolean;
  function Problem return Boolean;
  procedure Report(Where: in String);
  procedure Clear_Flags;
  function Raised_Inexact return Boolean;
  procedure IPower(I: Integer; S1: in MPFloat; S2: in out MPFloat);
  function NumDigits(P: MP_Prec_T; Base: Positive) return Size_T;
  function EffLast(F: Positive; N: String) return Positive;
  procedure Parse(N: in String; DigCount,ExpPos,NLast: out Integer);

  pragma Inline (NOP,ReturnTrue,IsZero,ReturnZero,Sign,Approx,Compare,Exponent,SetZero);
  pragma Inline_Always (Reformat,Num_Problem,Problem);

  Limb_Size: constant MP_Prec_T := MP_Prec_T(MP_Limb_T'Object_Size);
  D_Precision: constant MP_Prec_T := MP_Prec_T(Double'Machine_Mantissa); -- initial default
  LD_Precision: constant MP_Prec_T := MP_Prec_T(Long_Double'Machine_Mantissa);
  MP_Precision: MP_Prec_T := MP_Prec_T(Initial_Precision);
  Check_Flags: Boolean := False;

  RoundingDirection: constant MPFR_Rnd_T := GMP_RNDN;

  RZero: constant LLFloat := LLFloat(0);
  ROne:  constant LLFloat := LLFloat(1);
  RTwo:  constant LLFloat := LLFloat(2);
  RHalf: constant LLFloat := LLFloat(Half);

end MPFR.Floats;
