with Interfaces.C, Interfaces.C.Strings, MP_Arch;
use Interfaces.C, Interfaces.C.Strings, MP_Arch;

package MPFR is    --- see also mp.h, gmp.h, mpfr.h

  subtype MPFR_Base is Int range   2 .. 36;
  type MP_Exp_T_Ptr is access MP_Exp_T;

  type MPFR_T is private;

  type MPFR_Rnd_T is (GMP_RNDN, -- round to nearest
                      GMP_RNDZ, -- round toward zero
                      GMP_RNDU, -- round up
                      GMP_RNDD, -- round down
                      GMP_RND_MAX);

  for MPFR_Rnd_T use (GMP_RNDN    => 0,
                      GMP_RNDZ    => 1,
                      GMP_RNDU    => 2,
                      GMP_RNDD    => 3,
                      GMP_RND_MAX => 4 );

  --- Initialization Functions
  procedure MPFR_Init(R: in out MPFR_T);
  procedure MPFR_Init2(R: in out MPFR_T; Prec: in MP_Prec_T);
  procedure MPFR_Clear(R: in out MPFR_T);
  procedure MPFR_Set_Default_Prec(Prec: in MP_Prec_T);
  function  MPFR_Get_Default_Prec return MP_Prec_T;
  procedure MPFR_Set_Prec(R: in out MPFR_T; Prec: in MP_Prec_T);
  procedure MPFR_Set_Prec_Raw(R: in out MPFR_T; Prec: in MP_Prec_T);
  function MPFR_Get_Prec(R: MPFR_T) return MP_Prec_T;
  procedure MPFR_Prec_Round(R: in out MPFR_T; Prec: in MP_Prec_T; Rnd: in MPFR_Rnd_T);

  --- Assignment Functions
  procedure MPFR_Set(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Set_Si(Ter: out Int; ROp: in out MPFR_T; Op: in Long; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Set_Ld(Ter: out Int; ROp: in out MPFR_T; Op: in Long_Double; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Set_Str(Rep: out Int; R: in out MPFR_T; C: in Chars_Ptr; Base: in MPFR_Base; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Set_Zero(Op: in out MPFR_T; Sign: in Int);
  procedure MPFR_Swap(Op1,Op2: in out MPFR_T);

  --- Combined Initialization and Assignment Functions
  --  procedure MPFR_Init_Set(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  --  procedure MPFR_Init_Set_Si(Ter: out Int; ROp: in out MPFR_T; Op: in Long; Rnd: in MPFR_Rnd_T);
  --  procedure MPFR_Init_Set_Ld(Ter: out Int; ROp: in out MPFR_T; Op: in Long_Double; Rnd: in MPFR_Rnd_T);
  --  procedure MPFR_Init_Set_Str(Rep: out Int; R: in out MPFR_T; C: in Chars_Ptr; Base: in MPFR_Base; Rnd: in MPFR_Rnd_T);

  --- Conversion Functions
  function MPFR_Get_Ld(Op: MPFR_T; Rnd: MPFR_Rnd_T) return Long_Double;
  function MPFR_Get_Str(C: Chars_Ptr; ExpPtr: MP_Exp_T_Ptr; Base: MPFR_Base; NDigits: Size_T;
                                                                             Op: MPFR_T; Rnd: MPFR_Rnd_T) return Chars_Ptr;
  procedure MPFR_Free_Str(C: in Chars_Ptr);

  --- Integer Related Functions
  procedure MPFR_Integer_P(Rep: out Int; Op: in MPFR_T);
  procedure MPFR_Ceil(ROp: in out MPFR_T; Op: in MPFR_T);
  procedure MPFR_Floor(ROp: in out MPFR_T; Op: in MPFR_T);
  procedure MPFR_Round(ROp: in out MPFR_T; Op: in MPFR_T);

  --- Basic Arithmetic Functions
  procedure MPFR_Add(Ter: out Int; ROp: in out MPFR_T; Op1, Op2: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Add_Si(Ter: out Int; ROp: in out MPFR_T; Op1: in MPFR_T; Op2: in Long; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Sub(Ter: out Int; ROp: in out MPFR_T; Op1, Op2: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Mul(Ter: out Int; ROp: in out MPFR_T; Op1, Op2: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Mul_D(Ter: out Int; ROp: in out MPFR_T; Op1: in MPFR_T; Op2: in Double; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Sqr(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Div(Ter: out Int; ROp: in out MPFR_T; Op1, Op2: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Div_D(Ter: out Int; ROp: in out MPFR_T; Op1: in MPFR_T; Op2: in Double; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Sqrt(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Root(Ter: out Int; ROp: in out MPFR_T; Op1: in MPFR_T; Op2: in Unsigned_Long; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Pow_Si(Ter: out Int; ROp: in out MPFR_T; Op1: in MPFR_T; Op2: in Long; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Neg(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Abs(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);

  --- Comparison Functions
  function MPFR_Cmp(Op1, Op2: MPFR_T) return Int;
  function MPFR_Cmp_Ld(Op1: MPFR_T; Op2: Long_Double) return Int;
  function MPFR_Zero_P(Op: MPFR_T) return Int;
  function MPFR_NaN_P(Op: MPFR_T) return Int;
  function MPFR_Sgn(Op: MPFR_T) return Int;

  --- Special Functions
  procedure MPFR_Log(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Exp(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Cos(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Sin(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_ACos(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_ASin(Ter: out Int; ROp: in out MPFR_T; Op: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_FMA(Ter: out Int; ROp: in out MPFR_T; Op1, Op2, Op3: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_FMS(Ter: out Int; ROp: in out MPFR_T; Op1, Op2, Op3: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Const_Pi(Ter: out Int; ROp: in out MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Free_Cache;

  --- Miscellaneous Functions
  procedure MPFR_NextAbove(ROp: in out MPFR_T);
  procedure MPFR_NextBelow(ROp: in out MPFR_T);
  procedure MPFR_Min(Ter: out Int; ROp: in out MPFR_T; Op1, Op2: in MPFR_T; Rnd: in MPFR_Rnd_T);
  procedure MPFR_Max(Ter: out Int; ROp: in out MPFR_T; Op1, Op2: in MPFR_T; Rnd: in MPFR_Rnd_T);

  --- Exception Related Functions
  procedure MPFR_Clear_NaNFlag;
  procedure MPFR_Clear_Flags;
  function MPFR_Underflow_P return Int;
  function MPFR_Overflow_P return Int;
  function MPFR_NaNFlag_P return Int;
  function MPFR_InexFlag_P return Int;
  function MPFR_ERangeFlag_P return Int;

private

  Pragma Convention(C, MPFR_Rnd_T);

  type MP_Limb_T_Ptr is access all MP_Limb_T;  -- MP_Limb_A

  type MPFR_Struct is
    record
      MP_Prec: MP_Prec_T;
      MPFR_Sign: MP_Sign_T;
      MPFR_Exp : MP_Exp_T;
      MPFR_D   : MP_Limb_T_Ptr;
    end record;

  type MPFR_T   is array(1 .. 1) of MPFR_Struct;
  type MPFR_Ptr is access all MPFR_Struct;

  Pragma Convention (C, MPFR_Struct);
  Pragma Convention (C, MPFR_T);
  Pragma Convention (C, MPFR_Ptr);

  --- Initialization Functions
  pragma Import (C, MPFR_Init, "mpfr_init");
  pragma Import (C, MPFR_Init2, "mpfr_init2");
  pragma Import (C, MPFR_Clear, "mpfr_clear");
  pragma Import (C, MPFR_Set_Default_Prec, "mpfr_set_default_prec");
  pragma Import (C, MPFR_Get_Default_Prec, "mpfr_get_default_prec");
  pragma Import (C, MPFR_Set_Prec, "mpfr_set_prec");
  pragma Import (C, MPFR_Set_Prec_Raw, "mpfr_set_prec_raw");
  pragma Import (C, MPFR_Get_Prec, "mpfr_get_prec");
  pragma Import (C,  MPFR_Prec_Round, "mpfr_prec_round");

  --- Assignment Functions
  pragma Import (C, MPFR_Set, "mpfr_set");
  pragma Import_Valued_Procedure(MPFR_Set);
  pragma Import (C, MPFR_Set_Si, "mpfr_set_si");
  pragma Import_Valued_Procedure(MPFR_Set_Si);
  pragma Import (C, MPFR_Set_Ld, "mpfr_set_ld");
  pragma Import_Valued_Procedure(MPFR_Set_Ld);
  pragma Import (C, MPFR_Set_Zero, "mpfr_set_zero");
  pragma Import (C, MPFR_Swap, "mpfr_swap");
  pragma Import (C, MPFR_Set_Str, "mpfr_set_str");
  pragma Import_Valued_Procedure(MPFR_Set_Str);

  --- Combined Initialization and Assignment Functions
  --  pragma Import (C, MPFR_Init_Set, "mpfr_init_set");
  --  pragma Import_Valued_Procedure(MPFR_Init_Set);
  --  pragma Import (C, MPFR_Init_Set_Si, "mpfr_init_set_si");
  --  pragma Import_Valued_Procedure(MPFR_Init_Set_Si);
  --  pragma Import (C, MPFR_Init_Set_Ld, "mpfr_init_set_ld");
  --  pragma Import_Valued_Procedure(MPFR_Init_Set_Ld);
  --  pragma Import (C, MPFR_Init_Set_Str, "mpfr_init_set_str");
  --  pragma Import_Valued_Procedure(MPFR_Init_Set_Str);

  --- Conversion Functions
  pragma Import (C, MPFR_Get_Ld, "mpfr_get_ld");
  pragma Import (C, MPFR_Get_Str, "mpfr_get_str");
  pragma Import (C, MPFR_Free_Str, "mpfr_free_str");

  --- Integer Related Functions
  pragma Import (C, MPFR_Integer_P, "mpfr_integer_p");
  pragma Import_Valued_Procedure(MPFR_Integer_P);
  pragma Import (C, MPFR_Ceil, "mpfr_ceil");
  pragma Import (C, MPFR_Floor, "mpfr_floor");
  pragma Import (C, MPFR_Round, "mpfr_round");

  --- Basic Arithmetic Functions
  pragma Import (C, MPFR_Add, "mpfr_add");
  pragma Import_Valued_Procedure(MPFR_Add);
  pragma Import (C, MPFR_Add_Si, "mpfr_add_si");
  pragma Import_Valued_Procedure(MPFR_Add_Si);
  pragma Import (C, MPFR_Sub, "mpfr_sub");
  pragma Import_Valued_Procedure(MPFR_Sub);
  pragma Import (C, MPFR_Mul, "mpfr_mul");
  pragma Import_Valued_Procedure(MPFR_Mul);
  pragma Import (C, MPFR_Mul_D, "mpfr_mul_d");
  pragma Import_Valued_Procedure(MPFR_Mul_D);
  pragma Import (C, MPFR_Sqr, "mpfr_sqr");
  pragma Import_Valued_Procedure(MPFR_Sqr);
  pragma Import (C, MPFR_Div, "mpfr_div");
  pragma Import_Valued_Procedure(MPFR_Div);
  pragma Import (C, MPFR_Div_D, "mpfr_div_d");
  pragma Import_Valued_Procedure(MPFR_Div_D);
  pragma Import (C, MPFR_Sqrt, "mpfr_sqrt");
  pragma Import_Valued_Procedure(MPFR_Sqrt);
  pragma Import (C, MPFR_Root, "mpfr_root");
  pragma Import_Valued_Procedure(MPFR_Root);
  pragma Import (C, MPFR_Pow_Si, "mpfr_pow_si");
  pragma Import_Valued_Procedure(MPFR_Pow_Si);
  pragma Import (C, MPFR_Neg, "mpfr_neg");
  pragma Import_Valued_Procedure(MPFR_Neg);
  pragma Import (C, MPFR_Abs, "mpfr_abs");
  pragma Import_Valued_Procedure(MPFR_Abs);

  --- Comparison Functions
  pragma Import (C, MPFR_Cmp, "mpfr_cmp");
  pragma Import (C, MPFR_Cmp_Ld, "mpfr_cmp_ld");
  pragma Import (C, MPFR_Zero_P, "mpfr_zero_p");
  pragma Import (C, MPFR_NaN_P, "mpfr_nan_p");
  pragma Import (C, MPFR_Sgn, "mpfr_sgn");

  --- Special Functions
  pragma Import (C, MPFR_Log, "mpfr_log");
  pragma Import_Valued_Procedure(MPFR_Log);
  pragma Import (C, MPFR_Exp, "mpfr_exp");
  pragma Import_Valued_Procedure(MPFR_Exp);
  pragma Import (C, MPFR_Cos, "mpfr_cos");
  pragma Import_Valued_Procedure(MPFR_Cos);
  pragma Import (C, MPFR_Sin, "mpfr_sin");
  pragma Import_Valued_Procedure(MPFR_Sin);
  pragma Import (C, MPFR_ACos, "mpfr_acos");
  pragma Import_Valued_Procedure(MPFR_ACos);
  pragma Import (C, MPFR_ASin, "mpfr_asin");
  pragma Import_Valued_Procedure(MPFR_ASin);
  pragma Import (C, MPFR_FMA, "mpfr_fma");
  pragma Import_Valued_Procedure(MPFR_FMA);
  pragma Import (C, MPFR_FMS, "mpfr_fms");
  pragma Import_Valued_Procedure(MPFR_FMS);
  pragma Import (C,MPFR_Const_Pi, "mpfr_const_pi");
  pragma Import_Valued_Procedure(MPFR_Const_Pi);
  pragma Import (C,MPFR_Free_Cache, "mpfr_free_cache");

  --- Miscellaneous Functions
  pragma Import (C, MPFR_NextAbove, "mpfr_nextabove");
  pragma Import (C, MPFR_NextBelow, "mpfr_nextbelow");
  pragma Import (C, MPFR_Min, "mpfr_min");
  pragma Import_Valued_Procedure(MPFR_Min);
  pragma Import (C, MPFR_Max, "mpfr_max");
  pragma Import_Valued_Procedure(MPFR_Max);

  --- Exception Related Functions
  pragma Import (C, MPFR_Clear_NaNFlag, "mpfr_clear_nanflag");
  pragma Import (C, MPFR_Clear_Flags, "mpfr_clear_flags");
  pragma Import (C, MPFR_Underflow_P, "mpfr_underflow_p");
  pragma Import (C, MPFR_Overflow_P, "mpfr_overflow_p");
  pragma Import (C, MPFR_NaNFlag_P, "mpfr_nanflag_p");
  pragma Import (C, MPFR_InexFlag_P, "mpfr_inexflag_p");
  pragma Import (C, MPFR_ERangeFlag_P, "mpfr_erangeflag_p");

end MPFR;
