## 16 Internals ¶

This chapter is provided only for informational purposes and the various internals described here may change in future GMP releases. Applications expecting to be compatible with future releases should use only the documented interfaces described in previous chapters.

### 16.1 Integer Internals ¶

`mpz_t` variables represent integers using sign and magnitude, in space dynamically allocated and reallocated. The fields are as follows.

`_mp_size`

  The number of limbs, or the negative of that when representing a negative integer. Zero is represented by `_mp_size` set to zero, in which case the `_mp_d` data is undefined.

`_mp_d`

  A pointer to an array of limbs which is the magnitude. These are stored “little endian” as per the `mpn` functions, so `_mp_d[0]` is the least significant limb and `_mp_d[ABS(_mp_size)-1]` is the most significant. Whenever `_mp_size` is non-zero, the most significant limb is non-zero.

  Currently there’s always at least one readable limb, so for instance `mpz_get_ui` can fetch `_mp_d[0]` unconditionally (though its value is undefined if `_mp_size` is zero).

`_mp_alloc`

  `_mp_alloc` is the number of limbs currently allocated at `_mp_d`, and normally `_mp_alloc >= ABS(_mp_size)`. When an `mpz` routine is about to (or might be about to) increase `_mp_size`, it checks `_mp_alloc` to see whether there’s enough space, and reallocates if not. `MPZ_REALLOC` is generally used for this.

  `mpz_t` variables initialised with the `mpz_roinit_n` function or the `MPZ_ROINIT_N` macro have `_mp_alloc = 0` but can have a non-zero `_mp_size`. They can only be used as read-only constants. See Special Functions for details.

The various bitwise logical functions like `mpz_and` behave as if negative values were two’s complement. But sign and magnitude is always used internally, and necessary adjustments are made during the calculations. Sometimes this isn’t pretty, but sign and magnitude are best for other routines.

Some internal temporary variables are set up with `MPZ_TMP_INIT` and these have `_mp_d` space obtained from `TMP_ALLOC` rather than the memory allocation functions. Care is taken to ensure that these are big enough that no reallocation is necessary (since it would have unpredictable consequences).

`_mp_size` and `_mp_alloc` are `int`, although `mp_size_t` is usually a `long`. This is done to make the fields just 32 bits on some 64 bits systems, thereby saving a few bytes of data space but still providing plenty of range.

### 16.2 Rational Internals ¶

`mpq_t` variables represent rationals using an `mpz_t` numerator and denominator (see Integer Internals).

The canonical form adopted is denominator positive (and non-zero), no common factors between numerator and denominator, and zero uniquely represented as 0/1.

It’s believed that casting out common factors at each stage of a calculation is best in general. A GCD is an O(N^2) operation so it’s better to do a few small ones immediately than to delay and have to do a big one later. Knowing the numerator and denominator have no common factors can be used for example in `mpq_mul` to make only two cross GCDs necessary, not four.

This general approach to common factors is badly sub-optimal in the presence of simple factorizations or little prospect for cancellation, but GMP has no way to know when this will occur. As per Efficiency, that’s left to applications. The `mpq_t` framework might still suit, with `mpq_numref` and `mpq_denref` for direct access to the numerator and denominator, or of course `mpz_t` variables can be used directly.

### 16.3 Float Internals ¶

Efficient calculation is the primary aim of GMP floats and the use of whole limbs and simple rounding facilitates this.

`mpf_t` floats have a variable precision mantissa and a single machine word signed exponent. The mantissa is represented using sign and magnitude.

       most                   least
    significant            significant
       limb                   limb
                                _mp_d
     |---- _mp_exp --->           |
      _____ _____ _____ _____ _____
     |_____|_____|_____|_____|_____|
                       . <------------ radix point
      <-------- _mp_size --------->

The fields are as follows.

`_mp_size`

  The number of limbs currently in use, or the negative of that when representing a negative value. Zero is represented by `_mp_size` and `_mp_exp` both set to zero, and in that case the `_mp_d` data is unused. (In the future `_mp_exp` might be undefined when representing zero.)

`_mp_prec`

  The precision of the mantissa, in limbs. In any calculation the aim is to produce `_mp_prec` limbs of result (the most significant being non-zero).

`_mp_d`

  A pointer to the array of limbs which is the absolute value of the mantissa. These are stored “little endian” as per the `mpn` functions, so `_mp_d[0]` is the least significant limb and `_mp_d[ABS(_mp_size)-1]` the most significant.

  The most significant limb is always non-zero, but there are no other restrictions on its value, in particular the highest 1 bit can be anywhere within the limb.

  `_mp_prec+1` limbs are allocated to `_mp_d`, the extra limb being for convenience (see below). There are no reallocations during a calculation, only in a change of precision with `mpf_set_prec`.

`_mp_exp`

  The exponent, in limbs, determining the location of the implied radix point. Zero means the radix point is just above the most significant limb. Positive values mean a radix point offset towards the lower limbs and hence a value >= 1, as for example in the diagram above. Negative exponents mean a radix point further above the highest limb.

  Naturally the exponent can be any value, it doesn’t have to fall within the limbs as the diagram shows, it can be a long way above or a long way below. Limbs other than those included in the `{_mp_d,_mp_size}` data are treated as zero.

The `_mp_size` and `_mp_prec` fields are `int`, although the `mp_size_t` type is usually a `long`. The `_mp_exp` field is usually `long`. This is done to make some fields just 32 bits on some 64 bits systems, thereby saving a few bytes of data space but still providing plenty of precision and a very large range.

The following various points should be noted.

Low Zeros

  The least significant limbs `_mp_d[0]` etc can be zero, though such low zeros can always be ignored. Routines likely to produce low zeros check and avoid them to save time in subsequent calculations, but for most routines they’re quite unlikely and aren’t checked.

Mantissa Size Range

  The `_mp_size` count of limbs in use can be less than `_mp_prec` if the value can be represented in less. This means low precision values or small integers stored in a high precision `mpf_t` can still be operated on efficiently.

  `_mp_size` can also be greater than `_mp_prec`. Firstly a value is allowed to use all of the `_mp_prec+1` limbs available at `_mp_d`, and secondly when `mpf_set_prec_raw` lowers `_mp_prec` it leaves `_mp_size` unchanged and so the size can be arbitrarily bigger than `_mp_prec`.

Rounding

  All rounding is done on limb boundaries. Calculating `_mp_prec` limbs with the high non-zero will ensure the application requested minimum precision is obtained.

  The use of simple “trunc” rounding towards zero is efficient, since there’s no need to examine extra limbs and increment or decrement.

Bit Shifts

  Since the exponent is in limbs, there are no bit shifts in basic operations like `mpf_add` and `mpf_mul`. When differing exponents are encountered all that’s needed is to adjust pointers to line up the relevant limbs.

  Of course `mpf_mul_2exp` and `mpf_div_2exp` will require bit shifts, but the choice is between an exponent in limbs which requires shifts there, or one in bits which requires them almost everywhere else.

Use of `_mp_prec+1` Limbs

  The extra limb on `_mp_d` (`_mp_prec+1` rather than just `_mp_prec`) helps when an `mpf` routine might get a carry from its operation. `mpf_add` for instance will do an `mpn_add` of `_mp_prec` limbs. If there’s no carry then that’s the result, but if there is a carry then it’s stored in the extra limb of space and `_mp_size` becomes `_mp_prec+1`.

  Whenever `_mp_prec+1` limbs are held in a variable, the low limb is not needed for the intended precision, only the `_mp_prec` high limbs. But zeroing it out or moving the rest down is unnecessary. Subsequent routines reading the value will simply take the high limbs they need, and this will be `_mp_prec` if their target has that same precision. This is no more than a pointer adjustment, and must be checked anyway since the destination precision can be different from the sources.

  Copy functions like `mpf_set` will retain a full `_mp_prec+1` limbs if available. This ensures that a variable which has `_mp_size` equal to `_mp_prec+1` will get its full exact value copied. Strictly speaking this is unnecessary since only `_mp_prec` limbs are needed for the application’s requested precision, but it’s considered that an `mpf_set` from one variable into another of the same precision ought to produce an exact copy.

Application Precisions

  `__GMPF_BITS_TO_PREC` converts an application requested precision to an `_mp_prec`. The value in bits is rounded up to a whole limb then an extra limb is added since the most significant limb of `_mp_d` is only non-zero and therefore might contain only one bit.

  `__GMPF_PREC_TO_BITS` does the reverse conversion, and removes the extra limb from `_mp_prec` before converting to bits. The net effect of reading back with `mpf_get_prec` is simply the precision rounded up to a multiple of `mp_bits_per_limb`.

  Note that the extra limb added here for the high only being non-zero is in addition to the extra limb allocated to `_mp_d`. For example with a 32-bit limb, an application request for 250 bits will be rounded up to 8 limbs, then an extra added for the high being only non-zero, giving an `_mp_prec` of 9. `_mp_d` then gets 10 limbs allocated. Reading back with `mpf_get_prec` will take `_mp_prec` subtract 1 limb and multiply by 32, giving 256 bits.

  Strictly speaking, the fact that the high limb has at least one bit means that a float with, say, 3 limbs of 32-bits each will be holding at least 65 bits, but for the purposes of `mpf_t` it’s considered simply to be 64 bits, a nice multiple of the limb size.

### 16.4 Raw Output Internals ¶

`mpz_out_raw` uses the following format.

    +------+------------------------+
    | size |       data bytes       |
    +------+------------------------+

The size is 4 bytes written most significant byte first, being the number of subsequent data bytes, or the two’s complement negative of that when a negative integer is represented. The data bytes are the absolute value of the integer, written most significant byte first.

The most significant data byte is always non-zero, so the output is the same on all systems, irrespective of limb size.

In GMP 1, leading zero bytes were written to pad the data bytes to a multiple of the limb size. `mpz_inp_raw` will still accept this, for compatibility.

The use of “big endian” for both the size and data fields is deliberate, it makes the data easy to read in a hex dump of a file. Unfortunately it also means that the limb data must be reversed when reading or writing, so neither a big endian nor little endian system can just read and write `_mp_d`.

### 16.5 C++ Interface Internals ¶

A system of expression templates is used to ensure something like `a=b+c` turns into a simple call to `mpz_add` etc. For `mpf_class` the scheme also ensures the precision of the final destination is used for any temporaries within a statement like `f=w*x+y*z`. These are important features which a naive implementation cannot provide.

A simplified description of the scheme follows. The true scheme is complicated by the fact that expressions have different return types. For detailed information, refer to the source code.

To perform an operation, say, addition, we first define a “function object” evaluating it,

    struct __gmp_binary_plus
    {
      static void eval(mpf_t f, const mpf_t g, const mpf_t h)
      {
        mpf_add(f, g, h);
      }
    };

And an “additive expression” object,

    __gmp_expr<__gmp_binary_expr<mpf_class, mpf_class, __gmp_binary_plus> >
    operator+(const mpf_class &f, const mpf_class &g)
    {
      return __gmp_expr
        <__gmp_binary_expr<mpf_class, mpf_class, __gmp_binary_plus> >(f, g);
    }

The seemingly redundant `__gmp_expr<__gmp_binary_expr<…>>` is used to encapsulate any possible kind of expression into a single template type. In fact even `mpf_class` etc are `typedef` specializations of `__gmp_expr`.

Next we define assignment of `__gmp_expr` to `mpf_class`.

    template <class T>
    mpf_class & mpf_class::operator=(const __gmp_expr<T> &expr)
    {
      expr.eval(this->get_mpf_t(), this->precision());
      return *this;
    }
    template <class Op>
    void __gmp_expr<__gmp_binary_expr<mpf_class, mpf_class, Op> >::eval
    (mpf_t f, mp_bitcnt_t precision)
    {
      Op::eval(f, expr.val1.get_mpf_t(), expr.val2.get_mpf_t());
    }

where `expr.val1` and `expr.val2` are references to the expression’s operands (here `expr` is the `__gmp_binary_expr` stored within the `__gmp_expr`).

This way, the expression is actually evaluated only at the time of assignment, when the required precision (that of `f`) is known. Furthermore the target `mpf_t` is now available, thus we can call `mpf_add` directly with `f` as the output argument.

Compound expressions are handled by defining operators taking subexpressions as their arguments, like this:

    template <class T, class U>
    __gmp_expr
    <__gmp_binary_expr<__gmp_expr<T>, __gmp_expr<U>, __gmp_binary_plus> >
    operator+(const __gmp_expr<T> &expr1, const __gmp_expr<U> &expr2)
    {
      return __gmp_expr
        <__gmp_binary_expr<__gmp_expr<T>, __gmp_expr<U>, __gmp_binary_plus> >
        (expr1, expr2);
    }

And the corresponding specializations of `__gmp_expr::eval`:

    template <class T, class U, class Op>
    void __gmp_expr
    <__gmp_binary_expr<__gmp_expr<T>, __gmp_expr<U>, Op> >::eval
    (mpf_t f, mp_bitcnt_t precision)
    {
      // declare two temporaries
      mpf_class temp1(expr.val1, precision), temp2(expr.val2, precision);
      Op::eval(f, temp1.get_mpf_t(), temp2.get_mpf_t());
    }

The expression is thus recursively evaluated to any level of complexity and all subexpressions are evaluated to the precision of `f`.