--    GMPAda, binding to the Ada Language for the GNU MultiPrecision library.
--    Copyright (C) 2007-2017 Nicolas Boulenguez <nicolas.boulenguez@free.fr>
--
--    This program is free software: you can redistribute it and/or modify
--    it under the terms of the GNU General Public License as published by
--    the Free Software Foundation, either version 3 of the License, or
--    (at your option) any later version.
--
--    This program is distributed in the hope that it will be useful,
--    but WITHOUT ANY WARRANTY; without even the implied warranty of
--    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--    GNU General Public License for more details.
--
--    You should have received a copy of the GNU General Public License
--    along with this program.  If not, see <http://www.gnu.org/licenses/>.

with Interfaces.C; use Interfaces.C;
with Interfaces.C_Streams;
private with Interfaces.C.Pointers;
with Ada.Streams;
with GMP.Constants;

package GMP.Binding is

   pragma Preelaborate;

   Gmp_Version : String renames GMP.Constants.Gmp_Version;
   Mp_Bits_Per_Limb          : constant := GMP.Constants.Mp_Bits_Per_Limb;
   Gnu_Mp_Version            : constant := GMP.Constants.Gnu_Mp_Version;
   Gnu_Mp_Version_Minor      : constant := GMP.Constants.Gnu_Mp_Version_Minor;
   Gnu_Mp_Version_Patchlevel : constant
     := GMP.Constants.Gnu_Mp_Version_Patchlevel;

   type Mp_Exp_T is range -2**(GMP.Constants.Mp_Exp_T_Size - 1)
     .. 2**(GMP.Constants.Mp_Exp_T_Size - 1) - 1;
   for Mp_Exp_T'Size use GMP.Constants.Mp_Exp_T_Size;

   type Mp_Size_T is range -2**(GMP.Constants.Mp_Size_T_Size - 1)
     .. 2**(GMP.Constants.Mp_Size_T_Size - 1) - 1;
   for Mp_Size_T'Size use GMP.Constants.Mp_Size_T_Size;

   type Mp_Limb_T is mod 2**GMP.Constants.Mp_Limb_T_Size;
   for Mp_Limb_T'Size use GMP.Constants.Mp_Limb_T_Size;

   type Mpz_T is private;
   type Mpq_T is private;
   type Mpf_T is private;
   --  These types should be limited if this interface was ever to be
   --  used directly.

   type Mpz_T_Ptr is access all Mpz_T;

   type Gmp_Randstate_T is private;

   ---------------
   --  Integer  --
   ---------------

   --  Initialization

   procedure Mpz_Init (X : out Mpz_T);
   pragma Import (C, Mpz_Init, "mpz_init", "__gmpz_init");
   --  Initialize Integer, with space for n bits, and set its value to 0.

   procedure Mpz_Init2 (X :    out Mpz_T;
                        N : in     unsigned_long);
   pragma Import (C, Mpz_Init2, "mpz_init2", "__gmpz_init2");

   procedure Mpz_Clear (X : in out Mpz_T);
   pragma Import (C, Mpz_Clear, "mpz_clear", "__gmpz_clear");
   --  Free the space occupied by integer.
   --  Call this function for all mpz_t variables when you are done with them.

   procedure Mpz_Realloc2 (X : in out Mpz_T;
                           N : in     unsigned_long);
   pragma Import (C, Mpz_Realloc2, "mpz_realloc2", "__gmpz_realloc2");
   --  Change the space allocated for integer to n bits. The value in
   --  integer is preserved if it fits, or is set to 0 if not. This
   --  function can be used to increase the space for a variable in
   --  order to avoid repeated automatic reallocations, or to decrease
   --  it to give memory back to the heap.

   --  Assignment

   procedure Mpz_Set (Rop : in out Mpz_T;
                      Op  : in     Mpz_T);
   pragma Import (C, Mpz_Set, "mpz_set", "__gmpz_set");

   procedure Mpz_Set_Ui (Rop : in out Mpz_T;
                         Op  : in     unsigned_long);
   pragma Import (C, Mpz_Set_Ui, "mpz_set_ui", "__gmpz_set_ui");

   procedure Mpz_Set_Si (Rop : in out Mpz_T;
                         Op  : in     long);
   pragma Import (C, Mpz_Set_Si, "mpz_set_si", "__gmpz_set_si");

   procedure Mpz_Set_D (Rop : in out Mpz_T;
                        Op  : in     double);
   pragma Import (C, Mpz_Set_D, "mpz_set_d", "__gmpz_set_d");

   procedure Mpz_Set_Q (Rop : in out Mpz_T;
                        Op  : in     Mpq_T);
   pragma Import (C, Mpz_Set_Q, "mpz_set_q", "__gmpz_set_q");

   procedure Mpz_Set_F (Rop : in out Mpz_T;
                        Op  : in     Mpf_T);
   pragma Import (C, Mpz_Set_F, "mpz_set_f", "__gmpz_set_f");

   procedure Mpz_Set_Str (Result :    out int;
                          Rop    : in out Mpz_T;
                          Str    : in     char_array;
                          Base   : in     int);
   pragma Import (C, Mpz_Set_Str, "mpz_set_str", "__gmpz_set_str");
   pragma Import_Valued_Procedure (Mpz_Set_Str);
   --  set the value of rop from op.
   --  mpz_set_d, mpz_set_q and mpz_set_f truncate op to make it an integer.
   --  int mpz_set_str (mpz t rop, char *str, int base)
   --  Set the value of rop from str, a null-terminated C string in base base.
   --  White space is allowed in the string, and is simply ignored.

   procedure Mpz_Swap (Rop1, Rop2 : in out Mpz_T);
   pragma Import (C, Mpz_Swap, "mpz_swap", "__gmpz_swap");
   --  Swap the values rop1 and rop2 efficiently.

   --  Combined Initialization and Assignment
   --  Warning : Do not call for already initialized variables !

   procedure Mpz_Init_Set (Rop :    out Mpz_T;
                           Op  : in     Mpz_T);
   pragma Import (C, Mpz_Init_Set, "mpz_init_set", "__gmpz_init_set");

   procedure Mpz_Init_Set_Ui (Rop :    out Mpz_T;
                              Op  : in     unsigned_long);
   pragma Import (C, Mpz_Init_Set_Ui, "mpz_init_set_ui", "__gmpz_init_set_ui");

   procedure Mpz_Init_Set_Si (Rop :    out Mpz_T;
                              Op  : in     long);
   pragma Import (C, Mpz_Init_Set_Si, "mpz_init_set_si", "__gmpz_init_set_si");

   procedure Mpz_Init_Set_D (Rop :    out Mpz_T;
                             Op  : in     double);
   pragma Import (C, Mpz_Init_Set_D, "mpz_init_set_d", "__gmpz_init_set_d");
   --  Initialize rop with limb space and set the initial numeric
   --  value from op.

   procedure Mpz_Init_Set_Str (Result :    out int;
                               Rop    :    out Mpz_T;
                               Str    : in     char_array;
                               Base   : in     int);
   pragma Import (C, Mpz_Init_Set_Str, "mpz_init_set_str",
                  "__gmpz_init_set_str");
   pragma Import_Valued_Procedure (Mpz_Init_Set_Str);

   --  Initialize rop and set its value like mpz_set_str (see its
   --  documentation for details).  In C, mpz_init_set_str is a
   --  function that returns an int value. But in Ada, it needs to be
   --  a procedure since rop is modified by the call, and the return
   --  value is of little interest : If the string is a correct base
   --  base number, the function returns 0; if an error occurs it
   --  returns 1.  rop is initialized even if an error occurs. (I.e.,
   --  you have to call mpz_clear for it.)

   --  Conversion

   function Mpz_Get_Ui (Op : in Mpz_T)
                       return unsigned_long;
   pragma Import (C, Mpz_Get_Ui, "mpz_get_ui", "__gmpz_get_ui");
   --  Return the value of op as an unsigned long. If op is too big to
   --  fit an unsigned long then just the least significant bits that
   --  do fit are returned. The sign of op is ignored, only the
   --  absolute value is used.

   function Mpz_Get_Si (Op : in Mpz_T)
                       return long;
   pragma Import (C, Mpz_Get_Si, "mpz_get_si", "__gmpz_get_si");
   --  If op fits into a signed long int return the value of
   --  op. Otherwise return the least significant part of op, with the
   --  same sign as op. If op is too big to fit in a signed long int,
   --  the returned result is probably not very useful. To find out if
   --  the value will fit, use the function mpz_fits_slong_p.

   function Mpz_Get_D (Op : in Mpz_T)
                      return double;
   pragma Import (C, Mpz_Get_D, "mpz_get_d", "__gmpz_get_d");
   --  Convert op to a double, truncating if necessary (ie. rounding
   --  towards zero).  If the exponent from the conversion is too big,
   --  the result is system dependent. An infinity is returned where
   --  available. A hardware overflow trap may or may not occur.

   procedure Mpz_Get_D_2exp (Result :    out double;
                             Exp    :    out long;
                             Op     : in     Mpz_T);
   pragma Import (C, Mpz_Get_D_2exp, "mpz_get_d_2exp", "__gmpz_get_d_2exp");
   pragma Import_Valued_Procedure (Mpz_Get_D_2exp);
   --  Convert op to a double, truncating if necessary (ie. rounding
   --  towards zero), and returning the exponent separately.  The
   --  return value is in the range 0.5 <= |d| < 1 and the exponent is
   --  stored to *exp. d*2**exp is the (truncated) op value. If op is
   --  zero, the return is 0.0 and 0 is stored to *exp.  This is
   --  similar to the standard C frexp function.

   procedure Mpz_Get_Str (Str    :    out char_array;
                          Base   : in     int;
                          Op     : in     Mpz_T);
   pragma Import (C, Mpz_Get_Str, "mpz_get_str", "__gmpz_get_str");
   --  Better not use xmalloc, char_array is much cleaner. Ignore the
   --  result.

   --  Convert op to a string of digits in base base. The
   --  base argument may vary from 2 to 62 or from 2 to 36. For base
   --  in the range 2..36, digits and upper-case letters are used; for
   --  37..62, digits, upper-case letters, and lower-case letters (in
   --  that significance order) are used.  If str is NULL, the result
   --  string is allocated using the current allocation function. The
   --  block will be strlen(str)+1 bytes, that being exactly enough
   --  for the string and null-terminator.  If str is not NULL, it
   --  should point to a block of storage large enough for the result,
   --  that being mpz_sizeinbase (op, base) + 2. The two extra bytes
   --  are for a possible minus sign, and the null-terminator.  A
   --  pointer to the result string is returned, being either the
   --  allocated block, or the given str.


   --  Arithmetic

   procedure Mpz_Add (Rop      : in out Mpz_T;
                      Op1, Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Add, "mpz_add", "__gmpz_add");

   procedure Mpz_Add_Ui (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Add_Ui, "mpz_add_ui", "__gmpz_add_ui");
   --  set rop to op1 + op2.

   procedure Mpz_Sub (Rop      : in out Mpz_T;
                      Op1, Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Sub, "mpz_sub", "__gmpz_sub");

   procedure Mpz_Sub_Ui (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Sub_Ui, "mpz_sub_ui", "__gmpz_sub_ui");

   procedure Mpz_Ui_Sub (Rop : in out Mpz_T;
                         Op1 : in     unsigned_long;
                         Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Ui_Sub, "mpz_ui_sub", "__gmpz_ui_sub");
   --  set rop to op1 - op2.

   procedure Mpz_Mul (Rop      : in out Mpz_T;
                      Op1, Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Mul, "mpz_mul", "__gmpz_mul");

   procedure Mpz_Mul_Si (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     long);
   pragma Import (C, Mpz_Mul_Si, "mpz_mul_si", "__gmpz_mul_si");

   procedure Mpz_Mul_Ui (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Mul_Ui, "mpz_mul_ui", "__gmpz_mul_ui");
   --  set rop to op1 * op2.

   procedure Mpz_Addmul (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     Mpz_T);

   pragma Import (C, Mpz_Addmul, "mpz_addmul", "__gmpz_addmul");

   procedure Mpz_Addmul_Ui (Rop : in out Mpz_T;
                            Op1 : in     Mpz_T;
                            Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Addmul_Ui, "mpz_addmul_ui", "__gmpz_addmul_ui");
   --  set rop to rop + op1 * op2.

   procedure Mpz_Submul (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Submul, "mpz_submul", "__gmpz_submul");

   procedure Mpz_Submul_Ui (Rop : in out Mpz_T;
                            Op1 : in     Mpz_T;
                            Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Submul_Ui, "mpz_submul_ui", "__gmpz_submul_ui");
   --  set rop to rop - op1 * op2.

   procedure Mpz_Mul_2exp (Rop : in out Mpz_T;
                           Op1 : in     Mpz_T;
                           Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Mul_2exp, "mpz_mul_2exp", "__gmpz_mul_2exp");
   --  Set rop to op1 × 2op2. This operation can also be defined as a
   --  left shift by op2 bits.

   procedure Mpz_Neg (Rop : in out Mpz_T;
                      Op  : in     Mpz_T);
   pragma Import (C, Mpz_Neg, "mpz_neg", "__gmpz_neg");

   procedure Mpz_Abs (Rop : in out Mpz_T;
                      Op  : in     Mpz_T);
   pragma Import (C, Mpz_Abs, "mpz_abs", "__gmpz_abs");

   --  Division

   procedure Mpz_Cdiv_Q (Q : in out Mpz_T;
                         N : in     Mpz_T;
                         D : in     Mpz_T);
   pragma Import (C, Mpz_Cdiv_Q, "mpz_cdiv_q", "__gmpz_cdiv_q");

   procedure Mpz_Cdiv_R (R : in out Mpz_T;
                         N : in     Mpz_T;
                         D : in     Mpz_T);
   pragma Import (C, Mpz_Cdiv_R, "mpz_cdiv_r", "__gmpz_cdiv_r");

   procedure Mpz_Cdiv_QR (Q : in out Mpz_T;
                          R : in out Mpz_T;
                          N : in     Mpz_T;
                          D : in     Mpz_T);
   pragma Import (C, Mpz_Cdiv_QR, "mpz_cdiv_qr", "__gmpz_cdiv_qr");

   procedure Mpz_Cdiv_Q_Ui (Result :    out unsigned_long;
                            Q      : in out Mpz_T;
                            N      : in     Mpz_T;
                            D      : in     unsigned_long);
   pragma Import (C, Mpz_Cdiv_Q_Ui, "mpz_cdiv_q_ui", "__gmpz_cdiv_q_ui");
   pragma Import_Valued_Procedure (Mpz_Cdiv_Q_Ui);

   procedure Mpz_Cdiv_R_Ui (Result :    out unsigned_long;
                            R      : in out Mpz_T;
                            N      : in     Mpz_T;
                            D      : in     unsigned_long);
   pragma Import (C, Mpz_Cdiv_R_Ui, "mpz_cdiv_r_ui", "__gmpz_cdiv_r_ui");
   pragma Import_Valued_Procedure (Mpz_Cdiv_R_Ui);

   procedure Mpz_Cdiv_Qr_Ui (Result :    out unsigned_long;
                             Q      :    out Mpz_T;
                             R      : in out Mpz_T;
                             N      : in     Mpz_T;
                             D      : in     unsigned_long);
   pragma Import (C, Mpz_Cdiv_Qr_Ui, "mpz_cdiv_qr_ui", "__gmpz_cdiv_qr_ui");
   pragma Import_Valued_Procedure (Mpz_Cdiv_Qr_Ui);

   procedure Mpz_Cdiv_Ui (Result :    out unsigned_long;
                          N      : in     Mpz_T;
                          D      : in     unsigned_long);
   pragma Import (C, Mpz_Cdiv_Ui, "mpz_cdiv_ui", "__gmpz_cdiv_ui");
   pragma Import_Valued_Procedure (Mpz_Cdiv_Ui);

   procedure Mpz_Cdiv_Q_2exp (Q : in out Mpz_T;
                              N : in     Mpz_T;
                              B : in     unsigned_long);
   pragma Import (C, Mpz_Cdiv_Q_2exp, "mpz_cdiv_q_2exp", "__gmpz_cdiv_q_2exp");

   procedure Mpz_Cdiv_R_2exp (R : in out Mpz_T;
                              N : in     Mpz_T;
                              B : in     unsigned_long);
   pragma Import (C, Mpz_Cdiv_R_2exp, "mpz_cdiv_r_2exp", "__gmpz_cdiv_r_2exp");

   procedure Mpz_Fdiv_Q (Q : in out Mpz_T;
                         N : in     Mpz_T;
                         D : in     Mpz_T);
   pragma Import (C, Mpz_Fdiv_Q, "mpz_fdiv_q", "__gmpz_fdiv_q");

   procedure Mpz_Fdiv_R (R : in out Mpz_T;
                         N : in     Mpz_T;
                         D : in     Mpz_T);
   pragma Import (C, Mpz_Fdiv_R, "mpz_fdiv_r", "__gmpz_fdiv_r");


   procedure Mpz_Fdiv_QR (Q : in out Mpz_T;
                          R : in out Mpz_T;
                          N : in     Mpz_T;
                          D : in     Mpz_T);
   pragma Import (C, Mpz_Fdiv_QR, "mpz_fdiv_qr", "__gmpz_fdiv_qr");

   procedure Mpz_Fdiv_Q_Ui (Result :    out unsigned_long;
                            Q      : in out Mpz_T;
                            N      : in     Mpz_T;
                            D      : in     unsigned_long);
   pragma Import (C, Mpz_Fdiv_Q_Ui, "mpz_fdiv_q_ui", "__gmpz_fdiv_q_ui");
   pragma Import_Valued_Procedure (Mpz_Fdiv_Q_Ui);

   procedure Mpz_Fdiv_R_Ui (Result :    out unsigned_long;
                            R      : in out Mpz_T;
                            N      : in     Mpz_T;
                            D      : in     unsigned_long);
   pragma Import (C, Mpz_Fdiv_R_Ui, "mpz_fdiv_r_ui", "__gmpz_fdiv_r_ui");
   pragma Import_Valued_Procedure (Mpz_Fdiv_R_Ui);

   procedure Mpz_Fdiv_Qr_Ui (Result :    out unsigned_long;
                             Q      :    out Mpz_T;
                             R      : in out Mpz_T;
                             N      : in     Mpz_T;
                             D      : in     unsigned_long);
   pragma Import (C, Mpz_Fdiv_Qr_Ui, "mpz_fdiv_qr_ui", "__gmpz_fdiv_qr_ui");
   pragma Import_Valued_Procedure (Mpz_Fdiv_Qr_Ui);

   procedure Mpz_Fdiv_Ui (Result :    out unsigned_long;
                          N      : in     Mpz_T;
                          D      : in     unsigned_long);
   pragma Import (C, Mpz_Fdiv_Ui, "mpz_fdiv_ui", "__gmpz_fdiv_ui");
   pragma Import_Valued_Procedure (Mpz_Fdiv_Ui);

   procedure Mpz_Fdiv_Q_2exp (Q : in out Mpz_T;
                              N : in     Mpz_T;
                              B : in     unsigned_long);
   pragma Import (C, Mpz_Fdiv_Q_2exp, "mpz_fdiv_q_2exp", "__gmpz_fdiv_q_2exp");

   procedure Mpz_Fdiv_R_2exp (R : in out Mpz_T;
                              N : in     Mpz_T;
                              B : in     unsigned_long);
   pragma Import (C, Mpz_Fdiv_R_2exp, "mpz_fdiv_r_2exp", "__gmpz_fdiv_r_2exp");

   procedure Mpz_Tdiv_Q (Q : in out Mpz_T;
                         N : in     Mpz_T;
                         D : in     Mpz_T);
   pragma Import (C, Mpz_Tdiv_Q, "mpz_tdiv_q", "__gmpz_tdiv_q");

   procedure Mpz_Tdiv_R (R : in out Mpz_T;
                         N : in     Mpz_T;
                         D : in     Mpz_T);
   pragma Import (C, Mpz_Tdiv_R, "mpz_tdiv_r", "__gmpz_tdiv_r");

   procedure Mpz_Tdiv_QR (Q : in out Mpz_T;
                          R : in out Mpz_T;
                          N : in     Mpz_T;
                          D : in     Mpz_T);
   pragma Import (C, Mpz_Tdiv_QR, "mpz_tdiv_qr", "__gmpz_tdiv_qr");

   procedure Mpz_Tdiv_Q_Ui (Result :    out unsigned_long;
                            Q      : in out Mpz_T;
                            N      : in     Mpz_T;
                            D      : in     unsigned_long);
   pragma Import (C, Mpz_Tdiv_Q_Ui, "mpz_tdiv_q_ui", "__gmpz_tdiv_q_ui");
   pragma Import_Valued_Procedure (Mpz_Tdiv_Q_Ui);

   procedure Mpz_Tdiv_R_Ui (Result :    out unsigned_long;
                            R      : in out Mpz_T;
                            N      : in     Mpz_T;
                            D      : in     unsigned_long);
   pragma Import (C, Mpz_Tdiv_R_Ui, "mpz_tdiv_r_ui", "__gmpz_tdiv_r_ui");
   pragma Import_Valued_Procedure (Mpz_Tdiv_R_Ui);

   procedure Mpz_Tdiv_Qr_Ui (Result :    out unsigned_long;
                             Q      :    out Mpz_T;
                             R      : in out Mpz_T;
                             N      : in     Mpz_T;
                             D      : in     unsigned_long);
   pragma Import (C, Mpz_Tdiv_Qr_Ui, "mpz_tdiv_qr_ui", "__gmpz_tdiv_qr_ui");
   pragma Import_Valued_Procedure (Mpz_Tdiv_Qr_Ui);

   procedure Mpz_Tdiv_Ui (Result :    out unsigned_long;
                          N      : in     Mpz_T;
                          D      : in     unsigned_long);
   pragma Import (C, Mpz_Tdiv_Ui, "mpz_tdiv_ui", "__gmpz_tdiv_ui");
   pragma Import_Valued_Procedure (Mpz_Tdiv_Ui);

   procedure Mpz_Tdiv_Q_2exp (Q : in out Mpz_T;
                              N : in     Mpz_T;
                              B : in     unsigned_long);
   pragma Import (C, Mpz_Tdiv_Q_2exp, "mpz_tdiv_q_2exp", "__gmpz_tdiv_q_2exp");

   procedure Mpz_Tdiv_R_2exp (R : in out Mpz_T;
                              N : in     Mpz_T;
                              B : in     unsigned_long);
   pragma Import (C, Mpz_Tdiv_R_2exp, "mpz_tdiv_r_2exp", "__gmpz_tdiv_r_2exp");
   --  Divide n by d, forming a quotient q and/or remainder r.  For the
   --  2exp functions, d = 2b. The rounding is in three styles, each
   --  suiting different applications : "cdiv" : rounds q up towards
   --  +Inf, and r will have the opposite sign to d.  The c stands for
   --  "ceil".  "fdiv" : rounds q down towards -Inf, and r will have
   --  the same sign as d.  The f stands for "floor".  "tdiv" : rounds
   --  q towards zero, and r will have the same sign as n. The t
   --  stands for "truncate".

   --  In all cases q and r will satisfy n = qd + r, and r will satisfy
   --  0 <= |r| < |d|.  Note that for qr the same variable cannot be
   --  passed for both q and r, or results will be unpredictable.  For
   --  the ui variants the return value is the remainder, and in fact
   --  returning the remainder is all the div_ui functions do. For
   --  tdiv and cdiv the remainder can be negative, so for those the
   --  return value is the absolute value of the remainder.  For the
   --  2exp variants the divisor is 2b. These functions are
   --  implemented as right shifts and bit masks, but of course they
   --  round the same as the other functions.  For positive n both
   --  mpz_fdiv_q_2exp and mpz_tdiv_q_2exp are simple bitwise right
   --  shifts.  For negative n, mpz_fdiv_q_2exp is effectively an
   --  arithmetic right shift treating n as twos complement the same
   --  as the bitwise logical functions do, whereas mpz_tdiv_q_2exp
   --  effectively treats n as sign and magnitude.

   procedure Mpz_Mod (R : in out Mpz_T;
                      N : in     Mpz_T;
                      D : in     Mpz_T);
   pragma Import (C, Mpz_Mod, "mpz_mod", "__gmpz_mod");

   procedure Mpz_Mod_Ui (Result :    out unsigned_long;
                         R      : in out Mpz_T;
                         N      : in     Mpz_T;
                         D      : in     Mpz_T);
   pragma Import (C, Mpz_Mod_Ui, "mpz_mod_ui", "__gmpz_mod_ui");
   pragma Import_Valued_Procedure (Mpz_Mod_Ui);
   --  Set r to n mod d. The sign of the divisor is ignored; the
   --  result is always non-negative.  mpz_mod_ui is identical to
   --  mpz_fdiv_r_ui above, returning the remainder as well as setting
   --  r. See mpz_fdiv_ui above if only the return value is wanted.

   procedure Mpz_Divexact (Q    : in out Mpz_T;
                           N, D : in     Mpz_T);
   pragma Import (C, Mpz_Divexact, "mpz_divexact", "__gmpz_divexact");

   procedure Mpz_Divexact_Ui (Q : in out Mpz_T;
                              N : in     Mpz_T;
                              D : in     unsigned_long);
   pragma Import (C, Mpz_Divexact_Ui, "mpz_divexact_ui", "__gmpz_divexact_ui");
   --  Set q to n/d. These functions produce correct results only when
   --  it is known in advance that d divides n.  These routines are
   --  much faster than the other division functions, and are the best
   --  choice when exact division is known to occur, for example
   --  reducing a rational to lowest terms.

   function Mpz_Divisible_P (N : in Mpz_T;
                             D : in Mpz_T)
                            return int;
   pragma Import (C, Mpz_Divisible_P, "mpz_divisible_p", "__gmpz_divisible_p");

   function Mpz_Divisible_Ui_P (N : in Mpz_T;
                                D : in unsigned_long)
                               return int;
   pragma Import (C, Mpz_Divisible_Ui_P, "mpz_divisible_ui_p",
                  "__gmpz_divisible_ui_p");

   function Mpz_Divisible_2exp_P (N : in Mpz_T;
                                  B : in unsigned_long)
                                 return int;
   pragma Import (C, Mpz_Divisible_2exp_P, "mpz_divisible_2exp_p",
                  "__gmpz_divisible_2exp_p");
   --  Return non-zero if n is exactly divisible by d, or in the case
   --  of mpz_divisible_2exp_p by 2b.  n is divisible by d if there
   --  exists an integer q satisfying n = qd. Unlike the other
   --  division functions, d = 0 is accepted and following the rule it
   --  can be seen that only 0 is considered divisible by 0.

   function Mpz_Congruent_P (N : in Mpz_T;
                             C : in Mpz_T;
                             D : in Mpz_T)
                            return int;
   pragma Import (C, Mpz_Congruent_P, "mpz_congruent_p", "__gmpz_congruent_p");

   function Mpz_Congruent_Ui_P (N : in Mpz_T;
                                C : in unsigned_long;
                                D : in unsigned_long)
                               return int;
   pragma Import (C, Mpz_Congruent_Ui_P, "mpz_congruent_ui_p",
                  "__gmpz_congruent_ui_p");

   function Mpz_Congruent_2exp_P (N, C : in Mpz_T;
                                  B    : in unsigned_long)
                                 return int;
   pragma Import (C, Mpz_Congruent_2exp_P, "mpz_congruent_2exp_p",
                  "__gmpz_congruent_2exp_p");
   --  Return non-zero if n is congruent to c modulo d, or in the case
   --  of mpz_congruent_2exp_p modulo 2b.
   --  n is congruent to c mod d if there exists an integer q
   --  satisfying n = c +qd. Unlike the other division functions, d =
   --  0 is accepted and following the rule it can be seen that n and
   --  c are considered congruent mod 0 only when exactly equal.

   --  Exponentiation

   procedure Mpz_Powm (Rop    : in out Mpz_T;
                       Base   : in     Mpz_T;
                       Exp    : in     Mpz_T;
                       Modulo : in     Mpz_T);
   pragma Import (C, Mpz_Powm, "mpz_powm", "__gmpz_powm");

   procedure Mpz_Powm_Ui (Rop    : in out Mpz_T;
                          Base   : in     Mpz_T;
                          Exp    : in     unsigned_long;
                          Modulo : in     Mpz_T);
   pragma Import (C, Mpz_Powm_Ui, "mpz_powm_ui", "__gmpz_powm_ui");
   --  Set rop to baseexp mod modulo. Negative exp is supported if an
   --  inverse base^-1 mod modulo exists (See mpz_invert in section
   --  5.9). If an inverse doesn't exist then a divide by zero is
   --  raised.

   procedure Mpz_Pow_Ui (Rop          : in out Mpz_T;
                         Base         : in     Mpz_T;
                         Exp          : in     unsigned_long);
   pragma Import (C, Mpz_Pow_Ui, "mpz_pow_ui", "__gmpz_pow_ui");

   procedure Mpz_Ui_Pow_Ui (Rop    : in out Mpz_T;
                            Base   : in     unsigned_long;
                            Exp    : in     unsigned_long);
   pragma Import (C, Mpz_Ui_Pow_Ui, "mpz_ui_pow_ui", "__gmpz_ui_pow_ui");
   --  Set rop to base^exp. The case 00 yields 1.

   --  Root Extraction

   procedure Mpz_Root (Result :    out int;
                       Rop    : in out Mpz_T;
                       Op     : in     Mpz_T;
                       N      : in     unsigned_long);
   pragma Import (C, Mpz_Root, "mpz_root", "__gmpz_root");
   pragma Import_Valued_Procedure (Mpz_Root);
   --  Set rop to the truncated integer part of the nth root of op.
   --  Note : in C it is a function that return non-zero if the
   --  computation was exact, i.e., if op is rop to the nth power.

   procedure Mpz_Rootrem (Root      : in out Mpz_T;
                          Remainder : in out Mpz_T;
                          U         : in     Mpz_T;
                          N         : in     unsigned_long);
   pragma Import (C, Mpz_Rootrem, "mpz_rootrem", "__gmpz_rootrem");
   --  Set root to the truncated integer part of the nth root of u.
   --  Set rmndr to the remainder, (u - root**n)

   procedure Mpz_Sqrt (Rop    : in out Mpz_T;
                       Op     : in     Mpz_T);
   pragma Import (C, Mpz_Sqrt, "mpz_sqrt", "__gmpz_sqrt");
   --  Set rop to the truncated integer part of the square root of op.

   procedure Mpz_Sqrtrem (Rop1 : in out Mpz_T;
                          Rop2 : in out Mpz_T;
                          Op   : in     Mpz_T);
   pragma Import (C, Mpz_Sqrtrem, "mpz_sqrtrem", "__gmpz_sqrtrem");
   --  Set sqrt to the truncated integer part of the square root of op,
   --  like mpz_sqrt.  Set rmndr to the remainder (op - sqrt**2),
   --  which will be zero if op is a perfect square.  WARNING : If
   --  sqrt and rmndr are the same variable, the results are
   --  undefined.

   function Mpz_Perfect_Power_P (Op : in Mpz_T)
                                return int;
   pragma Import (C, Mpz_Perfect_Power_P, "mpz_perfect_power_p",
                  "__gmpz_perfect_power_p");
   --  Return non-zero if op is a perfect power, i.e., if there exist
   --  integers a and b, with b > 1, such that op = ab. Under this
   --  definition both 0 and 1 are considered to be perfect
   --  powers. Negative values of op are accepted, but of course can
   --  only be odd perfect powers.

   function Mpz_Perfect_Square_P (Op : in Mpz_T) return int;
   pragma Import (C, Mpz_Perfect_Square_P, "mpz_perfect_square_p",
                  "__gmpz_perfect_square_p");
   --  Return non-zero if op is a perfect square, i.e., if the square
   --  root of op is an integer. Under this definition both 0 and 1
   --  are considered to be perfect squares.

   --  Number Theory

   function Mpz_Probab_Prime_P (N    : in Mpz_T;
                                Reps : in int) return int;
   pragma Import (C, Mpz_Probab_Prime_P, "mpz_probab_prime_p",
                  "__gmpz_probab_prime_p");
   --  Determine whether n is prime. Return 2 if n is definitely prime,
   --  return 1 if n is probably prime (without being certain), or
   --  return 0 if n is definitely composite. This function does some
   --  trial divisions, then some Miller-Rabin probabilistic primality
   --  tests. reps controls how many such tests are done, 5 to 10 is a
   --  reasonable number, more will reduce the chances of a composite
   --  being returned as "probably prime". Miller-Rabin and similar
   --  tests can be more properly called compositeness tests. Numbers
   --  which fail are known to be composite but those which pass might
   --  be prime or might be composite. Only a few composites pass,
   --  hence those which pass are considered probably prime.

   procedure Mpz_Nextprime (Rop : in out Mpz_T;
                            Op  : in Mpz_T);
   pragma Import (C, Mpz_Nextprime, "mpz_nextprime", "__gmpz_nextprime");
   --  Set rop to the next prime greater than op. This function uses a
   --  probabilistic algorithm.  chance of a composite passing will be
   --  extremely small.

   procedure Mpz_Gcd (Rop : in out Mpz_T;
                      Op1 : in     Mpz_T;
                      Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Gcd, "mpz_gcd", "__gmpz_gcd");
   --  Set rop to the greatest common divisor of op1 and op2. The
   --  result is always positive even if one or both input operands
   --  are negative.

   procedure Mpz_Gcd_Ui (Result :    out unsigned_long;
                         Rop    : in out Mpz_T;
                         Op1    : in     Mpz_T;
                         Op2    : in     unsigned_long);
   pragma Import (C, Mpz_Gcd_Ui, "mpz_gcd_ui", "__gmpz_gcd_ui");
   pragma Import_Valued_Procedure (Mpz_Gcd_Ui);
   --  Compute the greatest common divisor of op1 and op2. If rop is
   --  not NULL, store the result there. If the result is small enough
   --  to fit in an unsigned long int, it is returned. If the result
   --  does not fit, 0 is returned, and the result is equal to the
   --  argument op1. Note that the result will always fit if op2 is
   --  non-zero.

   procedure Mpz_Gcdext (G : in out Mpz_T;
                         S : in out Mpz_T;
                         T : in out Mpz_T;
                         A : in     Mpz_T;
                         B : in     Mpz_T);
   procedure Mpz_Gcdext (G : in out Mpz_T;
                         S : in out Mpz_T;
                         T : in     Mpz_T_Ptr := null;
                         A : in     Mpz_T;
                         B : in     Mpz_T);
   --  The second form does not compute T.
   pragma Import (C, Mpz_Gcdext, "mpz_gcdext", "__gmpz_gcdext");
   --  Set g to the greatest common divisor of a and b, and in addition
   --  set s and t to coefficients satisfying as + bt = g. g is always
   --  positive, even if one or both of a and b are negative. The
   --  value of s and t are choosen such that |s| =< |b| and |t| =<
   --  |a|. If t is NULL then that value is not computed.

   procedure Mpz_Lcm (Rop : in out Mpz_T;
                      Op1 : in     Mpz_T;
                      Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Lcm, "mpz_lcm", "__gmpz_lcm");

   procedure Mpz_Lcm_Ui (Rop : in out Mpz_T;
                         Op1 : in     Mpz_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpz_Lcm_Ui, "mpz_lcm_ui", "__gmpz_lcm_ui");
   --  Set rop to the least common multiple of op1 and op2. rop is
   --  always positive, irrespective of the signs of op1 and op2. rop
   --  will be zero if either op1 or op2 is zero.

   procedure Mpz_Invert (Result :    out int;
                         Rop    : in out Mpz_T;
                         Op1    : in     Mpz_T;
                         Op2    : in     Mpz_T);
   pragma Import (C, Mpz_Invert, "mpz_invert", "__gmpz_invert");
   pragma Import_Valued_Procedure (Mpz_Invert);
   --  Compute the inverse of op1 modulo op2 and put the result in
   --  rop. If the inverse exists, the return value is non-zero and
   --  rop will satisfy 0 =< |rop| < |op2|. If the inverse doesn't
   --  exist the return value is zero and rop is undefined.

   function Mpz_Jacobi (A : in Mpz_T;
                        B : in Mpz_T)
                       return int;
   pragma Import (C, Mpz_Jacobi, "mpz_jacobi", "__gmpz_jacobi");
   --  Calculate the Jacobi symbol (a/b). This is defined only for b
   --  odd.

   function Mpz_Legendre (A : in Mpz_T;
                          B : in Mpz_T)
                         return int;
   pragma Import (C, Mpz_Legendre, "mpz_legendre", "__gmpz_legendre");
   --  Calculate the Legendre symbol (a/p). This is defined only for p
   --  an odd positive prime, and for such p it's identical to the
   --  Jacobi symbol.

   function Mpz_Kronecker (A : in Mpz_T;
                           B : in Mpz_T)
                          return int;
   pragma Import (C, Mpz_Kronecker, "mpz_kronecker",
                  "gmp_macro_mpz_kronecker");

   function Mpz_Kronecker_Si (A : in Mpz_T;
                              B : in long)
                             return int;
   pragma Import (C, Mpz_Kronecker_Si, "mpz_kronecker_si",
                  "__gmpz_kronecker_si");

   function Mpz_Kronecker_Ui (A : in Mpz_T;
                              B : in unsigned_long)
                             return int;
   pragma Import (C, Mpz_Kronecker_Ui, "mpz_kronecker_ui",
                  "__gmpz_kronecker_ui");

   function Mpz_Si_Kronecker (A : in long;
                              B : in Mpz_T)
                             return int;
   pragma Import (C, Mpz_Si_Kronecker, "mpz_si_kronecker",
                  "__gmpz_si_kronecker");

   function Mpz_Ui_Kronecker (A : in unsigned_long;
                              B : in Mpz_T)
                             return int;
   pragma Import (C, Mpz_Ui_Kronecker, "mpz_ui_kronecker",
                  "__gmpz_ui_kronecker");
   --  Calculate the Jacobi symbol (a/b), with the Kronecker extension
   --  (a/2) = (2/a) when a odd, or (a/2) = 0 when a even.  When b is
   --  odd the Jacobi symbol and Kronecker symbol are identical, so
   --  mpz_kronecker_ui etc can be used for mixed precision Jacobi
   --  symbols too.  For more information see Henri Cohen section
   --  1.4.2 (see Appendix B), or any number theory textbook.

   procedure Mpz_Remove (Result :    out unsigned_long;
                         Rop    : in out Mpz_T;
                         Op     : in     Mpz_T;
                         F      : in     Mpz_T);
   pragma Import (C, Mpz_Remove, "mpz_remove", "__gmpz_remove");
   pragma Import_Valued_Procedure (Mpz_Remove);
   --  Remove all occurrences of the factor f from op and store the
   --  result in rop.  The return value is how many such occurrences
   --  were removed.

   procedure Mpz_Fac_Ui (Rop : in out Mpz_T;
                         Op  : in     unsigned_long);
   pragma Import (C, Mpz_Fac_Ui, "mpz_fac_ui", "__gmpz_fac_ui");
   --  Set rop to op!, the factorial of op.

   procedure Mpz_Bin_Ui (Rop : in out Mpz_T;
                         N   : in     Mpz_T;
                         K   : in     unsigned_long);
   pragma Import (C, Mpz_Bin_Ui, "mpz_bin_ui", "__gmpz_bin_ui");

   procedure Mpz_Bin_Uiui (Rop : in out Mpz_T;
                           N   : in     unsigned_long;
                           K   : in     unsigned_long);
   pragma Import (C, Mpz_Bin_Uiui, "mpz_bin_uiui", "__gmpz_bin_uiui");
   --  Compute the binomial coefficient (n k) and store the result in
   --  rop.  Negative values of n are supported by mpz_bin_ui.

   procedure Mpz_Fib_Ui (Fn : in out Mpz_T;
                         N  : in     unsigned_long);
   pragma Import (C, Mpz_Fib_Ui, "mpz_fib_ui", "__gmpz_fib_ui");

   procedure Mpz_Fib2_Ui (Fn     : in out Mpz_T;
                          Fnsub1 : in out Mpz_T;
                          N      : in     unsigned_long);
   pragma Import (C, Mpz_Fib2_Ui, "mpz_fib2_ui", "__gmpz_fib2_ui");
   --  mpz_fib_ui sets fn to to F(n), the n'th Fibonacci
   --  number. mpz_fib2_ui sets fn to F(n), and fnsub1 to F(n-1).
   --  These functions are designed for calculating isolated Fibonacci
   --  numbers.  When a sequence of values is wanted it's best to
   --  start with mpz_fib2_ui and iterate the defining F(n+1) = F(n) +
   --  F(n-1) or similar.

   procedure Mpz_Lucnum_Ui (Ln : in out Mpz_T;
                            N  : in     unsigned_long);
   pragma Import (C, Mpz_Lucnum_Ui, "mpz_lucnum_ui", "__gmpz_lucnum_ui");

   procedure Mpz_Lucnum2_Ui (Ln     : in out Mpz_T;
                             Lnsub1 : in out Mpz_T;
                             N      : in     unsigned_long);
   pragma Import (C, Mpz_Lucnum2_Ui, "mpz_lucnum2_ui", "__gmpz_lucnum2_ui");
   --  mpz_lucnum_ui sets ln L(n) the n'th Lucas number. mpz_lucnum2_ui
   --  sets ln to L(n), and lnsub1 to L(n-1).  These functions are
   --  designed for calculating isolated Lucas numbers. When a
   --  sequence of values is wanted it's best to start with
   --  mpz_lucnum2_ui and iterate the defining L(n+1) = L(n) + L(n-1)
   --  or similar.  The Fibonacci numbers and Lucas numbers are
   --  related sequences, so it's never necessary to call both
   --  mpz_fib2_ui and mpz_lucnum2_ui. The formulas for going from
   --  Fibonacci to Lucas can be found in Section 16.7.5 [Lucas
   --  Numbers Algorithm], page 107, the reverse is straightforward
   --  too.

   --  Comparison

   function Mpz_Cmp (Op1 : in Mpz_T;
                     Op2 : in Mpz_T)
                    return int;
   pragma Import (C, Mpz_Cmp, "mpz_cmp", "__gmpz_cmp");

   function Mpz_Cmp_D (Op1 : in Mpz_T;
                       Op2 : in double)
                      return int;
   pragma Import (C, Mpz_Cmp_D, "mpz_cmp_d", "__gmpz_cmp_d");

   function Mpz_Cmp_Si (Op1 : in Mpz_T;
                        Op2 : in long)
                       return int;
   pragma Import (C, Mpz_Cmp_Si, "gmp_macro_mpz_cmp_si");

   function Mpz_Cmp_Ui (Op1 : in Mpz_T;
                        Op2 : in unsigned_long)
                       return int;
   pragma Import (C, Mpz_Cmp_Ui, "gmp_macro_mpz_cmp_ui");
   --  Compare op1 and op2. Return a positive value if op1 > op2 , zero
   --  if op1 = op2 , or a negative value if op1 < op2.

   function Mpz_Cmpabs (Op1 : in Mpz_T;
                        Op2 : in Mpz_T)
                       return int;
   pragma Import (C, Mpz_Cmpabs, "mpz_cmpabs", "__gmpz_cmpabs");

   function Mpz_Cmpabs_D (Op1 : in Mpz_T;
                          Op2 : in double)
                         return int;
   pragma Import (C, Mpz_Cmpabs_D, "mpz_cmpabs_d", "__gmpz_cmpabs_d");

   function Mpz_Cmpabs_Ui (Op1 : in Mpz_T;
                           Op2 : in unsigned_long)
                          return int;
   pragma Import (C, Mpz_Cmpabs_Ui, "mpz_cmpabs_ui", "__gmpz_cmpabs_ui");
   --  Compare the absolute values of op1 and op2. Return a positive
   --  value if |op1| > |op2|, zero if |op1| = |op2|, or a negative
   --  value if |op1| < |op2|.  mpz_cmpabs_d can be called with an
   --  infinity, but results are undefined for a NaN.

   function Mpz_Sgn (Op : in Mpz_T) return int;
   pragma Import (C, Mpz_Sgn, "gmp_macro_mpz_sgn");

   --  Logical and Bit Manipulation Functions

   procedure Mpz_And (Rop : in out Mpz_T;
                      Op1 : in     Mpz_T;
                      Op2 : in     Mpz_T);
   pragma Import (C, Mpz_And, "mpz_and", "__gmpz_and");

   procedure Mpz_Ior (Rop : in out Mpz_T;
                      Op1 : in     Mpz_T;
                      Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Ior, "mpz_ior", "__gmpz_ior");

   procedure Mpz_Xor (Rop : in out Mpz_T;
                      Op1 : in     Mpz_T;
                      Op2 : in     Mpz_T);
   pragma Import (C, Mpz_Xor, "mpz_xor", "__gmpz_xor");


   procedure Mpz_Com (Rop : in out Mpz_T;
                      Op  : in     Mpz_T);
   pragma Import (C, Mpz_Com, "mpz_com", "__gmpz_com");

   function Mpz_Popcount (Op : in Mpz_T)
                         return unsigned_long;
   pragma Import (C, Mpz_Popcount, "mpz_popcount", "__gmpz_popcount");

   function Mpz_Hamdist (Op1 : in Mpz_T;
                         Op2 : in Mpz_T)
                        return unsigned_long;
   pragma Import (C, Mpz_Hamdist, "mpz_hamdist", "__gmpz_hamdist");

   function Mpz_Scan0 (Op           : in Mpz_T;
                       Starting_Bit : in unsigned_long)
                      return unsigned_long;
   pragma Import (C, Mpz_Scan0, "mpz_scan0", "__gmpz_scan0");

   function Mpz_Scan1 (Op           : in Mpz_T;
                       Starting_Bit : in unsigned_long)
                      return unsigned_long;
   pragma Import (C, Mpz_Scan1, "mpz_scan1", "__gmpz_scan1");

   procedure Mpz_Setbit (Rop       : in out Mpz_T;
                         Bit_Index : in     unsigned_long);
   pragma Import (C, Mpz_Setbit, "mpz_setbit", "__gmpz_setbit");

   procedure Mpz_Clrbit (Rop       : in out Mpz_T;
                         Bit_Index : in     unsigned_long);
   pragma Import (C, Mpz_Clrbit, "mpz_clrbit", "__gmpz_clrbit");

   procedure Mpz_Combit (Rop       : in out Mpz_T;
                         Bit_Index : in     unsigned_long);
   pragma Import (C, Mpz_Combit, "mpz_combit", "__gmpz_combit");

   function Mpz_Tstbit (Op        : in Mpz_T;
                        Bit_Index : in unsigned_long)
                       return int;
   pragma Import (C, Mpz_Tstbit, "mpz_tstbit", "__gmpz_tstbit");

   --  Input and Output Functions

   function Mpz_Out_Str (Stream : in Interfaces.C_Streams.FILEs;
                         Base   : in int;
                         Op     : in Mpz_T)
                        return size_t;
   pragma Import (C, Mpz_Out_Str, "mpz_out_str", "__gmpz_out_str");

   procedure Mpz_Inp_Str (Result :    out size_t;
                          Rop    : in out Mpz_T;
                          Stream : in     Interfaces.C_Streams.FILEs;
                          Base   : in     int);
   pragma Import (C, Mpz_Inp_Str, "mpz_inp_str", "__gmpz_inp_str");
   pragma Import_Valued_Procedure (Mpz_Inp_Str);

   function Mpz_Out_Raw (Stream : in Interfaces.C_Streams.FILEs;
                         Op     : in Mpz_T)
                        return size_t;
   pragma Import (C, Mpz_Out_Raw, "mpz_out_raw", "__gmpz_out_raw");

   procedure Mpz_Inp_Raw (Result :    out size_t;
                          Rop    : in out Mpz_T;
                          Stream : in     Interfaces.C_Streams.FILEs);
   pragma Import (C, Mpz_Inp_Raw, "mpz_inp_raw", "__gmpz_inp_raw");
   pragma Import_Valued_Procedure (Mpz_Inp_Raw);

   --  Random Number

   procedure Mpz_Urandomb (Rop   : in out Mpz_T;
                           State : in out Gmp_Randstate_T;
                           N     : in     unsigned_long);
   pragma Import (C, Mpz_Urandomb, "mpz_urandomb", "__gmpz_urandomb");

   procedure Mpz_Urandomm (Rop   : in out Mpz_T;
                           State : in out Gmp_Randstate_T;
                           N     : in     Mpz_T);
   pragma Import (C, Mpz_Urandomm, "mpz_urandomm", "__gmpz_urandomm");

   procedure Mpz_Rrandomb (Rop   : in out Mpz_T;
                           State : in out Gmp_Randstate_T;
                           N     : in     unsigned_long);
   pragma Import (C, Mpz_Rrandomb, "mpz_rrandomb", "__gmpz_rrandomb");

   --  mpz_random and mpz_random2 are obsolete.

   --  Import and Export
   --  are not implemented yet.
   --  pragma Import (C, Mpz_Import, "mpz_import", "__gmpz_import");
   --  pragma Import (C, Mpz_Export, "mpz_export", "__gmpz_export");
   --  procedure Mpz_Import (Rop : in out Mpz_T;
   --                            Count : size_t;
   --                            Order : int;
   --                            Size : int;
   --                            Endian : int;
   --                            Nails : size_t;
   --                            Op : Void);

   --     function Mpz_Export (Rop : in outVoid;
   --                           Countp : size_t;
   --                           Order : int;
   --                           Size : int;
   --                           Endian : int;
   --                           Nails : size_t;
   --                           Op : Mpz_T)
   --                          return Void_*};


   --  Miscellaneous

   function Mpz_Fits_Ulong_P (Op : in Mpz_T)
                             return int;
   pragma Import (C, Mpz_Fits_Ulong_P, "mpz_fits_ulong_p",
                  "__gmpz_fits_ulong_p");

   function Mpz_Fits_Slong_P (Op : in Mpz_T)
                             return int;
   pragma Import (C, Mpz_Fits_Slong_P, "mpz_fits_slong_p",
                  "__gmpz_fits_slong_p");

   function Mpz_Fits_Uint_P (Op : in Mpz_T)
                            return int;
   pragma Import (C, Mpz_Fits_Uint_P, "mpz_fits_uint_p", "__gmpz_fits_uint_p");

   function Mpz_Fits_Sint_P (Op : in Mpz_T)
                            return int;
   pragma Import (C, Mpz_Fits_Sint_P, "mpz_fits_sint_p", "__gmpz_fits_sint_p");

   function Mpz_Fits_Ushort_P (Op : in Mpz_T)
                              return int;
   pragma Import (C, Mpz_Fits_Ushort_P, "mpz_fits_ushort_p",
                  "__gmpz_fits_ushort_p");

   function Mpz_Fits_Sshort_P (Op : in Mpz_T)
                              return int;
   pragma Import (C, Mpz_Fits_Sshort_P, "mpz_fits_sshort_p",
                  "__gmpz_fits_sshort_p");
   --  Return non-zero iff the value of op fits in an unsigned long
   --  int, signed long int, unsigned int, signed int, unsigned short
   --  int, or signed short int, respectively. Otherwise, return zero.

   function Mpz_Odd_P (Op : in Mpz_T)
                      return int;
   pragma Import (C, Mpz_Odd_P, "gmp_macro_mpz_odd_p");

   function Mpz_Even_P (Op : in Mpz_T)
                       return int;
   pragma Import (C, Mpz_Even_P, "gmp_macro_mpz_even_p");
   --  Determine whether op is odd or even, respectively. Return
   --  non-zero if yes, zero if no.

   function Mpz_Sizeinbase (Op   : in Mpz_T;
                            Base : in int)
                           return size_t;
   pragma Import (C, Mpz_Sizeinbase, "mpz_sizeinbase", "__gmpz_sizeinbase");
   --  Return the size of op measured in number of digits in the given
   --  base. base can vary from 2 to 62. The sign of op is ignored,
   --  just the absolute value is used. The result will be either
   --  exact or 1 too big. If base is a power of 2, the result is
   --  always exact. If op is zero the return value is always 1.  This
   --  function can be used to determine the space required when
   --  converting op to a string. The right amount of allocation is
   --  normally two more than the value returned by mpz_sizeinbase,
   --  one extra for a minus sign and one for the null-terminator.  It
   --  will be noted that mpz_sizeinbase(op,2) can be used to locate
   --  the most significant 1 bit in op, counting from 1. (Unlike the
   --  bitwise functions which start from 0, See Section 5.11 LOGICAL
   --  AND BIT MANIPULATION FUNCTIONS).

   function Mpz_Getlimbn (Op : in Mpz_T;
                          N  : in Mp_Size_T)
                         return Mp_Limb_T;
   pragma Import (C, Mpz_Getlimbn, "mpz_getlimbn", "__gmpz_getlimbn");

   function Mpz_Size (Op : in Mpz_T) return size_t;
   pragma Import (C, Mpz_Size, "mpz_size", "__gmpz_size");

   ---------------
   -- Rationals --
   ---------------

   --  All rational arithmetic functions assume operands have a
   --  canonical form, and canonicalize their result. The canonical
   --  from means that the denominator and the numerator have no
   --  common factors, and that the denominator is positive. Zero has
   --  the unique representation 0/1.  Pure assignment functions do
   --  not canonicalize the assigned variable.  It is the
   --  responsibility of the user to canonicalize the assigned
   --  variable before any arithmetic operations are performed on that
   --  variable.

   procedure Mpq_Canonicalize (Op : in out Mpq_T);
   pragma Import (C, Mpq_Canonicalize, "mpq_canonicalize",
                  "__gmpq_canonicalize");
   --  Remove any factors that are common to the numerator and
   --  denominator of op, and make the denominator positive.

   --  Initialization and Assignment

   procedure Mpq_Init (Dest_Rational : out Mpq_T);
   pragma Import (C, Mpq_Init, "mpq_init", "__gmpq_init");

   procedure Mpq_Clear (Rational_Number : in out Mpq_T);
   pragma Import (C, Mpq_Clear, "mpq_clear", "__gmpq_clear");
   --  Initialize dest_rational and set it to 0/1. Each variable should
   --  normally only be initialized once, or at least cleared out
   --  (using the function mpq_clear) between each initialization.
   --  Free the space occupied by rational number. Make sure to call
   --  this function for all mpq_t variables when you are done with
   --  them.

   procedure Mpq_Set (Rop : in out Mpq_T;
                      Op  : in     Mpq_T);
   pragma Import (C, Mpq_Set, "mpq_set", "__gmpq_set");

   procedure Mpq_Set_Z (Rop : in out Mpq_T;
                        Op  : in     Mpz_T);
   pragma Import (C, Mpq_Set_Z, "mpq_set_z", "__gmpq_set_z");
   --  Assign rop from op.

   procedure Mpq_Set_Ui (Rop : in out Mpq_T;
                         Op1 : in     unsigned_long;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpq_Set_Ui, "mpq_set_ui", "__gmpq_set_ui");

   procedure Mpq_Set_Si (Rop : in out Mpq_T;
                         Op1 : in     long;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpq_Set_Si, "mpq_set_si", "__gmpq_set_si");
   --  Set the value of rop to op1/op2. Note that if op1 and op2 have
   --  common factors, rop has to be passed to mpq_canonicalize before
   --  any operations are performed on rop.

   procedure Mpq_Set_Str (Result :    out int;
                          Rop    : in out Mpq_T;
                          Str    : in     char_array;
                          Base   : in     int);
   pragma Import (C, Mpq_Set_Str, "mpq_set_str", "__gmpq_set_str");
   pragma Import_Valued_Procedure (Mpq_Set_Str);
   --  Set rop from a null-terminated string str in the given base. The
   --  string can be an integer like "41" or a fraction like
   --  "41/152". The fraction must be in canonical form or if not then
   --  mpq_canonicalize must be called.  The numerator and optional
   --  denominator are parsed the same as in mpz_set_str The base can
   --  vary from 2 to 62, or if base is 0 then the leading characters
   --  are used: 0x or 0X for hex, 0b or 0B for binary, 0 for octal,
   --  or decimal otherwise.

   procedure Mpq_Swap (Rop1 : in out Mpq_T;
                       Rop2 : in out Mpq_T);
   pragma Import (C, Mpq_Swap, "mpq_swap", "__gmpq_swap");
   --  Swap the values rop1 and rop2 efficiently.

   --  Conversion

   function Mpq_Get_D (Op : in Mpq_T)
                      return double;
   pragma Import (C, Mpq_Get_D, "mpq_get_d", "__gmpq_get_d");
   --  Convert op to a double, truncating if necessary (ie. rounding
   --  towards zero).  If the exponent from the conversion is too big
   --  or too small to fit a double then the result is system
   --  dependent. For too big an infinity is returned when
   --  available. For too small 0.0 is normally returned. Hardware
   --  overflow, underflow and denorm traps may or may not occur.

   procedure Mpq_Set_D (Rop : in out Mpq_T;
                        Op  : in     double);
   pragma Import (C, Mpq_Set_D, "mpq_set_d", "__gmpq_set_d");

   procedure Mpq_Set_F (Rop : in out Mpq_T;
                        Op  : in     Mpf_T);
   pragma Import (C, Mpq_Set_F, "mpq_set_f", "__gmpq_set_f");
   --  Set rop to the value of op. There is no rounding, this
   --  conversion is exact.

   procedure Mpq_Get_Str (Str    :    out char_array;
                          Base   : in     int;
                          Op     : in     Mpq_T);
   pragma Import (C, Mpq_Get_Str, "mpq_get_str", "__gmpq_get_str");
   --  Convert op to a string of digits in base base. The base may vary
   --  from 2 to 36.  The string will be of the form "num/den", or if
   --  the denominator is 1 then just "num". If str is NULL, the
   --  result string is allocated using the current allocation
   --  function. The block will be strlen(str)+1 bytes, that being
   --  exactly enough for the string and null-terminator.  If str is
   --  not NULL, it should point to a block of storage large enough
   --  for the result, that being mpz_sizeinbase (mpq_numref(op),
   --  base) + mpz_sizeinbase (mpq_denref(op), base) + 3 The three
   --  extra bytes are for a possible minus sign, possible slash, and
   --  the null-terminator. A pointer to the result string is
   --  returned, being either the allocated block, or the given str.

   --  Better not use xmalloc, char_array is much cleaner. Ignore the
   --  result.

   --  Arithmetic

   procedure Mpq_Add (Sum     : in out Mpq_T;
                      Addend1 : in     Mpq_T;
                      Addend2 : in     Mpq_T);
   pragma Import (C, Mpq_Add, "mpq_add", "__gmpq_add");
   --  Set sum to addend1 + addend2.

   procedure Mpq_Sub (Difference : in out Mpq_T;
                      Minuend    : in     Mpq_T;
                      Subtrahend : in     Mpq_T);
   pragma Import (C, Mpq_Sub, "mpq_sub", "__gmpq_sub");
   --  Set difference to minuend - subtrahend

   procedure Mpq_Mul (Product      : in out Mpq_T;
                      Multiplier   : in     Mpq_T;
                      Multiplicand : in     Mpq_T);
   pragma Import (C, Mpq_Mul, "mpq_mul", "__gmpq_mul");
   --  Set product to multiplier * multiplicand

   procedure Mpq_Mul_2exp (Rop : in out Mpq_T;
                           Op1 : in     Mpq_T;
                           Op2 : in     unsigned_long);
   pragma Import (C, Mpq_Mul_2exp, "mpq_mul_2exp", "__gmpq_mul_2exp");
   --  Set rop to op1 * 2**op2

   procedure Mpq_Div (Quotient : in out Mpq_T;
                      Dividend : in     Mpq_T;
                      Divisor  : in     Mpq_T);
   pragma Import (C, Mpq_Div, "mpq_div", "__gmpq_div");
   --  Set quotient to dividend / divisor

   procedure Mpq_Div_2exp (Rop : in out Mpq_T;
                           Op1 : in     Mpq_T;
                           Op2 : in     unsigned_long);
   pragma Import (C, Mpq_Div_2exp, "mpq_div_2exp", "__gmpq_div_2exp");
   --  Set rop to op1 / 2**op2

   procedure Mpq_Neg (Negated_Operand : in out Mpq_T;
                      Operand         : in     Mpq_T);
   pragma Import (C, Mpq_Neg, "mpq_neg", "__gmpq_neg");
   --  Set negated operand to -operand.

   procedure Mpq_Abs (Rop : in out Mpq_T;
                      Op  : in     Mpq_T);
   pragma Import (C, Mpq_Abs, "mpq_abs", "__gmpq_abs");
   --  Set rop to the absolute value of op.

   procedure Mpq_Inv (Inverted_Number : in out Mpq_T;
                      Number          : in     Mpq_T);
   pragma Import (C, Mpq_Inv, "mpq_inv", "__gmpq_inv");
   --  Set inverted number to 1/number. If the new denominator is zero,
   --  this routine will divide by zero.

   --  Comparison

   function Mpq_Cmp (Op1 : in Mpq_T;
                     Op2 : in Mpq_T)
                    return int;
   pragma Import (C, Mpq_Cmp, "mpq_cmp", "__gmpq_cmp");
   --  Compare op1 and op2. Return a positive value if op1 > op2, zero
   --  if op1 = op2, and a negative value if op1 < op2. To determine
   --  if two rationals are equal, mpq_equal is faster than mpq_cmp.

   function Mpq_Cmp_Ui (Op1  : in Mpq_T;
                        Num2 : in unsigned_long;
                        Den2 : in unsigned_long)
                       return int;
   pragma Import (C, Mpq_Cmp_Ui, "gmp_macro_mpq_cmp_ui");

   function Mpq_Cmp_Si (Op1  : in Mpq_T;
                        Num2 : in long;
                        Den2 : in unsigned_long)
                       return int;
   pragma Import (C, Mpq_Cmp_Si, "gmp_macro_mpq_cmp_si");

   function Mpq_Sgn (Op : in Mpq_T) return int;
   pragma Import (C, Mpq_Sgn, "gmp_macro_mpq_sgn");

   function Mpq_Equal (Op1 : in Mpq_T;
                       Op2 : in Mpq_T)
                      return int;
   pragma Import (C, Mpq_Equal, "mpq_equal", "__gmpq_equal");
   --  Return non-zero if op1 and op2 are equal, zero if they are
   --  non-equal.  Although mpq_cmp can be used for the same purpose,
   --  this function is much faster.

   --  Applying Integer Functions to Rationals

   --  The set of mpq functions is quite small. In particular, there
   --  are few functions for either input or output. The following
   --  functions give direct access to the numerator and denominator
   --  of an mpq_t.  Note that if an assignment to the numerator
   --  and/or denominator could take an mpq_t out of the canonical
   --  then mpq_canonicalize must be called before any other mpq
   --  functions are applied to that mpq_t.

   function Mpq_Numref (Op : in Mpq_T) return Mpz_T_Ptr;
   pragma Import (C, Mpq_Numref, "gmp_macro_mpq_numref");

   function Mpq_Denref (Op : in Mpq_T) return Mpz_T_Ptr;
   pragma Import (C, Mpq_Denref, "gmp_macro_mpq_denref");

   procedure Mpq_Get_Num (Numerator : in out Mpz_T;
                          Rational  : in     Mpq_T);
   pragma Import (C, Mpq_Get_Num, "mpq_get_num", "__gmpq_get_num");

   procedure Mpq_Get_Den (Denominator : in out Mpz_T;
                          Rational    : in     Mpq_T);
   pragma Import (C, Mpq_Get_Den, "mpq_get_den", "__gmpq_get_den");

   procedure Mpq_Set_Num (Rational  : in out Mpq_T;
                          Numerator : in     Mpz_T);
   pragma Import (C, Mpq_Set_Num, "mpq_set_num", "__gmpq_set_num");

   procedure Mpq_Set_Den (Rational    : in out Mpq_T;
                          Denominator : in     Mpz_T);
   pragma Import (C, Mpq_Set_Den, "mpq_set_den", "__gmpq_set_den");
   --  Get or set the numerator or denominator of a rational.

   --  Input and Output

   --  NOTE : <stdio.h> must have been included before gmp.h during
   --  compilation to allow "gmp.h" to define prototypes for these
   --  functions..  Passing a NULL pointer for a stream argument to
   --  any of these functions will make them read from stdin and write
   --  to stdout, respectively.

   function Mpq_Out_Str (Stream : in Interfaces.C_Streams.FILEs;
                         Base   : in int;
                         Op     : in Mpq_T)
                        return size_t;
   pragma Import (C, Mpq_Out_Str, "mpq_out_str", "__gmpq_out_str");
   --  Output op on stdio stream stream, as a string of digits in base
   --  base.

   procedure Mpq_Inp_Str (Result :    out size_t;
                          Rop    : in out Mpq_T;
                          Stream : in     Interfaces.C_Streams.FILEs;
                          Base   : in     int);
   pragma Import (C, Mpq_Inp_Str, "mpq_inp_str", "__gmpq_inp_str");
   pragma Import_Valued_Procedure (Mpq_Inp_Str);

   --------------------
   -- Floating-point --
   --------------------

   procedure Mpf_Set_Default_Prec (Prec : in unsigned_long);
   pragma Import (C, Mpf_Set_Default_Prec, "mpf_set_default_prec",
                  "__gmpf_set_default_prec");

   function Mpf_Get_Default_Prec return unsigned_long;
   pragma Import (C, Mpf_Get_Default_Prec, "mpf_get_default_prec",
                  "__gmpf_get_default_prec");
   --  Set the default precision to be at least prec bits. All
   --  subsequent calls to mpf_init will use this precision, but
   --  previously initialized variables are unaffected.  Return the
   --  default precision actually used.

   procedure Mpf_Init (X : out Mpf_T);
   pragma Import (C, Mpf_Init, "mpf_init", "__gmpf_init");

   procedure Mpf_Init2 (X    :    out Mpf_T;
                        Prec : in     unsigned_long);
   pragma Import (C, Mpf_Init2, "mpf_init2", "__gmpf_init2");
   --  Initialize x to 0, and set its precision to be at least prec
   --  bits.  Do not call if already Initialized !

   procedure Mpf_Clear (X : in out Mpf_T);
   pragma Import (C, Mpf_Clear, "mpf_clear", "__gmpf_clear");
   --  Free the space occupied by x. Make sure to call this function
   --  for all mpf_t variables when you are done with them.

   function Mpf_Get_Prec (Op : in Mpf_T)
                         return unsigned_long;
   pragma Import (C, Mpf_Get_Prec, "mpf_get_prec", "__gmpf_get_prec");

   procedure Mpf_Set_Prec (Rop   : in out Mpf_T;
                           Prec : in     unsigned_long);
   pragma Import (C, Mpf_Set_Prec, "mpf_set_prec", "__gmpf_set_prec");

   procedure Mpf_Set_Prec_Raw (Rop  : in out Mpf_T;
                               Prec : in     unsigned_long);
   pragma Import (C, Mpf_Set_Prec_Raw, "mpf_set_prec_raw",
                  "__gmpf_set_prec_raw");

   --  Assignment

   procedure Mpf_Set (Rop : in out Mpf_T;
                      Op  : in     Mpf_T);
   pragma Import (C, Mpf_Set, "mpf_set", "__gmpf_set");

   procedure Mpf_Set_Ui (Rop : in out Mpf_T;
                         Op  : in     unsigned_long);
   pragma Import (C, Mpf_Set_Ui, "mpf_set_ui", "__gmpf_set_ui");

   procedure Mpf_Set_Si (Rop : in out Mpf_T;
                         Op  : in     long);
   pragma Import (C, Mpf_Set_Si, "mpf_set_si", "__gmpf_set_si");

   procedure Mpf_Set_D (Rop : in out Mpf_T;
                        Op  : in     double);
   pragma Import (C, Mpf_Set_D, "mpf_set_d", "__gmpf_set_d");

   procedure Mpf_Set_Z (Rop : in out Mpf_T;
                        Op  : in     Mpz_T);
   pragma Import (C, Mpf_Set_Z, "mpf_set_z", "__gmpf_set_z");

   procedure Mpf_Set_Q (Rop : in out Mpf_T;
                        Op  : in     Mpq_T);
   pragma Import (C, Mpf_Set_Q, "mpf_set_q", "__gmpf_set_q");
   --  Set the value of rop from op.

   procedure Mpf_Set_Str (Result :    out int;
                          Rop    : in out Mpf_T;
                          Str    : in     char_array;
                          Base   : in     int);
   pragma Import (C, Mpf_Set_Str, "mpf_set_str", "__gmpf_set_str");
   pragma Import_Valued_Procedure (Mpf_Set_Str);

   procedure Mpf_Swap (Rop1 : in out Mpf_T;
                       Rop2 : in out Mpf_T);
   pragma Import (C, Mpf_Swap, "mpf_swap", "__gmpf_swap");

   --  Combined Initialization and Assignment

   procedure Mpf_Init_Set (Rop  :   out Mpf_T;
                           Op  : in     Mpf_T);
   pragma Import (C, Mpf_Init_Set, "mpf_init_set", "__gmpf_init_set");

   procedure Mpf_Init_Set_Ui (Rop :    out Mpf_T;
                              Op  : in     unsigned_long);
   pragma Import (C, Mpf_Init_Set_Ui, "mpf_init_set_ui", "__gmpf_init_set_ui");

   procedure Mpf_Init_Set_Si (Rop :    out Mpf_T;
                              Op  : in     long);
   pragma Import (C, Mpf_Init_Set_Si, "mpf_init_set_si", "__gmpf_init_set_si");

   procedure Mpf_Init_Set_D (Rop :    out Mpf_T;
                             Op  : in     double);
   pragma Import (C, Mpf_Init_Set_D, "mpf_init_set_d", "__gmpf_init_set_d");
   --  Initialize rop and set its value from op.

   procedure Mpf_Init_Set_Str (Result :    out int;
                               Rop    : in out Mpf_T;
                               Str    : in     char_array;
                               Base   : in     int);
   pragma Import (C, Mpf_Init_Set_Str, "mpf_init_set_str",
                  "__gmpf_init_set_str");
   pragma Import_Valued_Procedure (Mpf_Init_Set_Str);
   --  Initialize rop and set its value from the string in str.  Note
   --  that rop is initialized even if an error occurs. (I.e., you
   --  have to call mpf_clear for it.)  The precision of rop will be
   --  taken from the active default precision, as set by
   --  mpf_set_default_prec.

   --  Conversion

   function Mpf_Get_D (Op : in Mpf_T)
                      return double;
   pragma Import (C, Mpf_Get_D, "mpf_get_d", "__gmpf_get_d");

   procedure Mpf_Get_D_2exp (Ret :    out double;
                             Exp :    out long;
                             Op  : in     Mpf_T);
   pragma Import (C, Mpf_Get_D_2exp, "mpf_get_d_2exp", "__gmpf_get_d_2exp");
   pragma Import_Valued_Procedure (Mpf_Get_D_2exp);

   function Mpf_Get_Si (Op : in Mpf_T)
                       return long;
   pragma Import (C, Mpf_Get_Si, "mpf_get_si", "__gmpf_get_si");

   function Mpf_Get_Ui (Op : in Mpf_T)
                       return unsigned_long;
   pragma Import (C, Mpf_Get_Ui, "mpf_get_ui", "__gmpf_get_ui");

   procedure Mpf_Get_Str (Str      :    out char_array;
                          Expptr   :    out Mp_Exp_T;
                          Base     : in     int;
                          N_Digits : in     size_t;
                          Op       : in     Mpf_T);
   pragma Import (C, Mpf_Get_Str, "mpf_get_str", "__gmpf_get_str");
   --  Convert op to a string of digits in base base. The base argument
   --  may vary from 2 to 62 or from 2 to 36. Up to n_digits digits
   --  will be generated. Trailing zeros are not returned.  No more
   --  digits than can be accurately represented by op are ever
   --  generated. If n_digits is 0 then that accurate maximum number
   --  of digits are generated.

   --  Better not use xmalloc, char_array is much cleaner. Ignore the
   --  result.


   --  Arithmetic

   procedure Mpf_Add (Rop : in out Mpf_T;
                      Op1 : in     Mpf_T;
                      Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Add, "mpf_add", "__gmpf_add");

   procedure Mpf_Add_Ui (Rop : in out Mpf_T;
                         Op1 : in     Mpf_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Add_Ui, "mpf_add_ui", "__gmpf_add_ui");
   --  Set rop to op1 + op2 .

   procedure Mpf_Sub (Rop : in out Mpf_T;
                      Op1 : in     Mpf_T;
                      Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Sub, "mpf_sub", "__gmpf_sub");

   procedure Mpf_Ui_Sub (Rop : in out Mpf_T;
                         Op1 : in     unsigned_long;
                         Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Ui_Sub, "mpf_ui_sub", "__gmpf_ui_sub");

   procedure Mpf_Sub_Ui (Rop : in out Mpf_T;
                         Op1 : in     Mpf_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Sub_Ui, "mpf_sub_ui", "__gmpf_sub_ui");
   --  Set rop to op1 - op2.

   procedure Mpf_Mul (Rop : in out Mpf_T;
                      Op1 : in     Mpf_T;
                      Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Mul, "mpf_mul", "__gmpf_mul");

   procedure Mpf_Mul_Ui (Rop : in out Mpf_T;
                         Op1 : in     Mpf_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Mul_Ui, "mpf_mul_ui", "__gmpf_mul_ui");
   --  Set rop to op1 * op2 .

   --  Division is undefined if the divisor is zero, and passing a zero
   --  divisor to the divide functions will make these functions
   --  intentionally divide by zero. This lets the user handle
   --  arithmetic exceptions in these functions in the same manner as
   --  other arithmetic exceptions.
   procedure Mpf_Div (Rop : in out Mpf_T;
                      Op1 : in     Mpf_T;
                      Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Div, "mpf_div", "__gmpf_div");

   procedure Mpf_Ui_Div (Rop : in out Mpf_T;
                         Op1 : in     unsigned_long;
                         Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Ui_Div, "mpf_ui_div", "__gmpf_ui_div");

   procedure Mpf_Div_Ui (Rop : in out Mpf_T;
                         Op1 : in     Mpf_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Div_Ui, "mpf_div_ui", "__gmpf_div_ui");
   --  Set rop to op1 / op2.

   procedure Mpf_Sqrt (Rop : in out Mpf_T;
                       Op  : in     Mpf_T);
   pragma Import (C, Mpf_Sqrt, "mpf_sqrt", "__gmpf_sqrt");

   procedure Mpf_Sqrt_Ui (Rop : in out Mpf_T;
                          Op  : in     unsigned_long);
   pragma Import (C, Mpf_Sqrt_Ui, "mpf_sqrt_ui", "__gmpf_sqrt_ui");

   procedure Mpf_Pow_Ui (Rop : in out Mpf_T;
                         Op1 : in     Mpf_T;
                         Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Pow_Ui, "mpf_pow_ui", "__gmpf_pow_ui");

   procedure Mpf_Neg (Rop : in out Mpf_T;
                      Op  : in     Mpf_T);
   pragma Import (C, Mpf_Neg, "mpf_neg", "__gmpf_neg");

   procedure Mpf_Abs (Rop : in out Mpf_T;
                      Op  : in     Mpf_T);
   pragma Import (C, Mpf_Abs, "mpf_abs", "__gmpf_abs");

   procedure Mpf_Mul_2exp (Rop  : in out Mpf_T;
                           Op1 : in     Mpf_T;
                           Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Mul_2exp, "mpf_mul_2exp", "__gmpf_mul_2exp");

   procedure Mpf_Div_2exp (Rop  : in out Mpf_T;
                           Op1 : in     Mpf_T;
                           Op2 : in     unsigned_long);
   pragma Import (C, Mpf_Div_2exp, "mpf_div_2exp", "__gmpf_div_2exp");

   --  Comparison

   function Mpf_Cmp (Op1 : in Mpf_T;
                     Op2 : in Mpf_T)
                    return int;
   pragma Import (C, Mpf_Cmp, "mpf_cmp", "__gmpf_cmp");

   function Mpf_Cmp_D (Op1 : in Mpf_T;
                       Op2 : in double)
                      return int;
   pragma Import (C, Mpf_Cmp_D, "mpf_cmp_d", "__gmpf_cmp_d");

   function Mpf_Cmp_Ui (Op1 : in Mpf_T;
                        Op2 : in unsigned_long)
                       return int;
   pragma Import (C, Mpf_Cmp_Ui, "mpf_cmp_ui", "__gmpf_cmp_ui");

   function Mpf_Cmp_Si (Op1 : in Mpf_T;
                        Op2 : in long)
                       return int;
   pragma Import (C, Mpf_Cmp_Si, "mpf_cmp_si", "__gmpf_cmp_si");
   --  Compare op1 and op2. Return a positive value if op1 > op2, zero
   --  if op1 = op2 , and a negative value if op1 < op2 .

   function Mpf_Eq (Op1 : in Mpf_T;
                    Op2 : in Mpf_T;
                    Op3 : in unsigned_long)
                   return int;
   pragma Import (C, Mpf_Eq, "mpf_eq", "__gmpf_eq");

   procedure Mpf_Reldiff (Rop : in out Mpf_T;
                          Op1 : in     Mpf_T;
                          Op2 : in     Mpf_T);
   pragma Import (C, Mpf_Reldiff, "mpf_reldiff", "__gmpf_reldiff");

   function Mpf_Sgn (Op : in Mpf_T) return int;
   pragma Import (C, Mpf_Sgn, "gmp_macro_mpf_sgn");

   --  Input and Output

   function Mpf_Out_Str (Stream   : in Interfaces.C_Streams.FILEs;
                         Base     : in int;
                         N_Digits : in size_t;
                         Op       : in Mpf_T)
                        return size_t;
   pragma Import (C, Mpf_Out_Str, "mpf_out_str", "__gmpf_out_str");

   procedure Mpf_Inp_Str (Result :    out size_t;
                          Rop    : in out Mpf_T;
                          Stream : in     Interfaces.C_Streams.FILEs;
                          Base   : in     int);
   pragma Import (C, Mpf_Inp_Str, "mpf_inp_str", "__gmpf_inp_str");
   pragma Import_Valued_Procedure (Mpf_Inp_Str);

   --  Miscellaneous

   procedure Mpf_Ceil (Rop : in out Mpf_T;
                       Op  : in     Mpf_T);
   pragma Import (C, Mpf_Ceil, "mpf_ceil", "__gmpf_ceil");

   procedure Mpf_Floor (Rop : in out Mpf_T;
                        Op  : in     Mpf_T);
   pragma Import (C, Mpf_Floor, "mpf_floor", "__gmpf_floor");

   procedure Mpf_Trunc (Rop : in out Mpf_T;
                        Op  : in     Mpf_T);
   pragma Import (C, Mpf_Trunc, "mpf_trunc", "__gmpf_trunc");

   function Mpf_Integer_P (Op : in Mpf_T)
                          return int;
   pragma Import (C, Mpf_Integer_P, "mpf_integer_p", "__gmpf_integer_p");

   function Mpf_Fits_Ulong_P (Op : in Mpf_T)
                             return int;
   pragma Import (C, Mpf_Fits_Ulong_P, "mpf_fits_ulong_p",
                  "__gmpf_fits_ulong_p");

   function Mpf_Fits_Slong_P (Op : in Mpf_T)
                             return int;
   pragma Import (C, Mpf_Fits_Slong_P, "mpf_fits_slong_p",
                  "__gmpf_fits_slong_p");

   function Mpf_Fits_Uint_P (Op : in Mpf_T)
                            return int;
   pragma Import (C, Mpf_Fits_Uint_P, "mpf_fits_uint_p", "__gmpf_fits_uint_p");

   function Mpf_Fits_Sint_P (Op : in Mpf_T)
                            return int;
   pragma Import (C, Mpf_Fits_Sint_P, "mpf_fits_sint_p", "__gmpf_fits_sint_p");

   function Mpf_Fits_Ushort_P (Op : in Mpf_T)
                              return int;
   pragma Import (C, Mpf_Fits_Ushort_P, "mpf_fits_ushort_p",
                  "__gmpf_fits_ushort_p");

   function Mpf_Fits_Sshort_P (Op : in Mpf_T)
                              return int;
   pragma Import (C, Mpf_Fits_Sshort_P, "mpf_fits_sshort_p",
                  "__gmpf_fits_sshort_p");

   procedure Mpf_Urandomb (Rop    : in out Mpf_T;
                           State : in out Gmp_Randstate_T;
                           Nbits : in     unsigned_long);
   pragma Import (C, Mpf_Urandomb, "mpf_urandomb", "__gmpf_urandomb");

   procedure Mpf_Random2 (Rop      : in out Mpf_T;
                          Max_Size : in     Mp_Size_T;
                          Exp      : in     Mp_Exp_T);
   pragma Import (C, Mpf_Random2, "mpf_random2", "__gmpf_random2");

   --------------------
   --  Random Number --
   --------------------

   --  Random State Initialization --

   procedure Gmp_Randinit_Default (State : out Gmp_Randstate_T);
   pragma Import (C, Gmp_Randinit_Default, "mp_randinit_default",
                  "__gmp_randinit_default");

   procedure Gmp_Randinit_Mt (State : out Gmp_Randstate_T);
   pragma Import (C, Gmp_Randinit_Mt, "mp_randinit_mt", "__gmp_randinit_mt");

   procedure Gmp_Randinit_Lc_2exp (State :    out Gmp_Randstate_T;
                                   A     : in     Mpz_T;
                                   C     : in     unsigned_long;
                                   M2exp : in     unsigned_long);
   pragma Import (C, Gmp_Randinit_Lc_2exp, "mp_randinit_lc_2exp",
                  "__gmp_randinit_lc_2exp");

   procedure Gmp_Randinit_Lc_2exp_Size (Result :    out int;
                                        State  :    out Gmp_Randstate_T;
                                        Size   : in     unsigned_long);
   pragma Import (C, Gmp_Randinit_Lc_2exp_Size, "mp_randinit_lc_2exp_size",
                  "__gmp_randinit_lc_2exp_size");
   pragma Import_Valued_Procedure (Gmp_Randinit_Lc_2exp_Size);

   procedure Gmp_Randinit_Set (Rop :    out Gmp_Randstate_T;
                               Op  : in     Gmp_Randstate_T);
   pragma Import (C, Gmp_Randinit_Set, "mp_randinit_set",
                  "__gmp_randinit_set");

   --  gmp_rand_init is obsolete.

   procedure Gmp_Randclear (State : in out Gmp_Randstate_T);
   pragma Import (C, Gmp_Randclear, "mp_randclear", "__gmp_randclear");

   --  Random State Seeding

   procedure Gmp_Randseed (State : in out Gmp_Randstate_T;
                           Seed  : in     Mpz_T);
   pragma Import (C, Gmp_Randseed, "mp_randseed", "__gmp_randseed");

   procedure Gmp_Randseed_Ui (State : in out Gmp_Randstate_T;
                              Seed  : in     unsigned_long);
   pragma Import (C, Gmp_Randseed_Ui, "mp_randseed_ui", "__gmp_randseed_ui");

   --  Random State Miscellaneous

   procedure Gmp_Urandomb_Ui (Result :    out unsigned_long;
                              State  : in out Gmp_Randstate_T;
                              N      : in     unsigned_long);
   pragma Import (C, Gmp_Urandomb_Ui, "mp_urandomb_ui", "__gmp_urandomb_ui");

   procedure Gmp_Urandomm_Ui (Result :    out unsigned_long;
                              State  : in out Gmp_Randstate_T;
                              N      : in     unsigned_long);
   pragma Import (C, Gmp_Urandomm_Ui, "mp_urandomm_ui", "__gmp_urandomm_ui");

private

   type Mp_Limb_T_Array is array (size_t range <>) of aliased Mp_Limb_T;
   package Limbs is new Pointers (size_t, Mp_Limb_T, Mp_Limb_T_Array, 0);

   type Mpz_T is
      record
         Mp_Alloc : int;
         Mp_Size  : int;
         Mp_D     : Limbs.Pointer;
      end record;
   for Mpz_T use
      record
         Mp_Alloc at GMP.Constants.Mpz_Alloc_Start
           range 0 .. GMP.Constants.Mpz_Alloc_Length - 1;
         Mp_Size  at GMP.Constants.Mpz_Size_Start
           range 0 .. GMP.Constants.Mpz_Size_Length - 1;
         Mp_D     at GMP.Constants.Mpz_D_Start
           range 0 .. GMP.Constants.Mpz_D_Length - 1;
      end record;
   for Mpz_T'Size use GMP.Constants.Mpz_Alloc_Length
      + GMP.Constants.Mpz_Size_Length + GMP.Constants.Mpz_D_Length;
   pragma Convention (C, Mpz_T);

   procedure Read (Stream : access Ada.Streams.Root_Stream_Type'Class;
                   Item   :   out  Mpz_T);
   for Mpz_T'Read use Read;
   procedure Write (Stream : access Ada.Streams.Root_Stream_Type'Class;
                    Item   : in     Mpz_T);
   for Mpz_T'Write use Write;

   type Mpq_T is new char_array (1 .. GMP.Constants.Sizeof_Mpq_T);
   type Mpf_T is new char_array (1 .. GMP.Constants.Sizeof_Mpf_T);
   type Gmp_Randstate_t is new char_array
     (1 .. GMP.Constants.Sizeof_Gmp_Randstate_T);

end GMP.Binding;
