A Tour of NTL: Using NTL with GMP

#

A Tour of NTL: Using NTL with GMP

GMP is the GNU Multi-Precision library. You can get more information about it, as well as the latest version from here.

Briefly, GMP is a library for long integer arithmetic. It has hand-crafted assembly routines for a wide variety of architectures. For basic operations, like integer multiplication, it can be several times faster than NTL's traditional long integer package.

As of version 9.6.3, NTL uses GMP by default. You can disable GMP by passing `NTL_GMP_LIP=off` as an option to NTL's `configure` script. If you disable the use of GMP, NTL uses a long integer package derived from Arjen Lenstra's LIP package. This is not recommended: GMP is much faster.

Even if you do not use GMP, you should still read the section below on backward compatabilty so that you can write portable code and avoid deprecated constructs.

Note: GMP is thread safe, so you should feel free to use it in a thread-safe build of NTL. However, it is is not entirely exception friendly (it may abort a running program, but only in some very extreme and unusal circumstances).

## Downloading and building GMP

Many unix distributions now include GMP by default. However, even if it is included, it is recommended to build it from source. The reason is that the system-installed GMP is typically not well optimized, as it often targets a generic instruction set, rather than the instruction set on your actual machine. It is actually very easy to build and install GMP from source.

Download GMP from here. You will get a file `gmp-XXX.tar.xz`.

Now do the following:

       % tar -xf gmp-XXX.tar.xz
       % cd gmp-XXX
       % ./configure --prefix=$HOME/.local
       % make
       % make check
       % make install

This will build, test, and install GMP in `$HOME/.local`. Of course, change `$HOME/.local` to whatever you want. You will find the GMP header files in `$HOME/.local/include` and the compiled binaries in `$HOME/.local/lib`.

By default, this is will install both a static and shared library. You can supply the option `--disable-shared` to the `configure` script, if you only want static libraries. If you do this, you may also consider passing the `--with-pic` option if you want another shared library to be able to call functions in GMP.

You need to make sure that the NTL configure script knows where to find GMP when you are builing NTL. As discussed discussed in here, you can do this by passing `GMP_PREFIX=$HOME/.local` or `DEF_PREFIX=$HOME/.local` to NTL's configure script.

Also when you link and run a program that uses NTL, you have to make sure that the GMP library is found at link time and, depending on the system, possibly at run time. The best way to see how to do this is to look at the file `USER_MAKEFILE.txt` installed in NTL's include directory — again, see here for details.

When using NTL with GMP, as a user of NTL, you do not need to know or understand anything about the the GMP library. So while there is detailed documentation available about how to use GMP, you do not have to read it. The programming interface to the long integer package completely hides implementation details.

## Backward compatbility

This section is only relevant for very old programs that use NTL.

With version 5.0 of NTL, some aspects of the programming interface were 'deprecated' so as to allow the use of another long integer package, such as GMP, as the long integer package.

Prior to version 5.0, the macro `NTL_NBITS` was defined, along with the macro `NTL_RADIX` defined to be `(1L << NTL_NBITS)`. While these macros are still available when using NTL's traditional long integer package (i.e., when `NTL_GMP_LIP` is not set), they are not available when using the GMP as the long integer package (i.e., when `NTL_GMP_LIP` is set). Furthermore, when writing portable programs, one should avoid these macros.

Also, the static function `long ZZ::digit(const ZZ &, long);` is defined when using traditional long integer arithmetic, but is not available when using GMP as the long integer package, and in any case, its use should be avoided when writing portable programs.

Instead of the above macros, one should use the followng macros:

       NTL_ZZ_NBITS -- number of bits in a limb;
                       a ZZ is represented as a sequence of limbs.

       NTL_SP_NBITS -- max number of bits in a "single-precision" number

       NTL_WSP_NBITS -- max number of bits in a "wide single-precision" number

The following relations hold:

       NTL_SP_NBITS <= NTL_WSP_NBITS <= NTL_ZZ_NBITS
       26 <= NTL_SP_NBITS <= min(NTL_BITS_PER_LONG-2, NTL_DOUBLE_PRECISION-3)
       NTL_WSP_NBITS <= NTL_BITS_PER_LONG-2

Note that `NTL_ZZ_NBITS` may be less than, equal to, or greater than `NTL_BITS_PER_LONG` -- no particular relationship should be assumed to hold. In particular, expressions like `(1L << NTL_ZZ_BITS)` might overflow.

"single-precision" numbers are meant to be used in conjunction with the single-precision modular arithmetic routines.

"wide single-precision" numbers are meant to be used in conjunction with the `ZZ` arithmetic routines for optimal efficiency.

Note that when using traditional long integer arithmetic, we have

        NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS.

The following auxilliary macros are also defined:

    NTL_FRADIX -- double-precision value of 2^NTL_ZZ_NBITS
    NTL_SP_BOUND -- (1L << NTL_SP_NBITS)
    NTL_WSP_BOUND -- (1L << NTL_WSP_NBITS)

Note that for a `ZZ` `n`, `n.size()` returns the number of "limbs" of `n`. This is supported with either traditional or GMP integer arithemtic. Note, however, that some old codes might write `n.size() <= 1` as a way to test if `NumBits(n) <= NTL_NBITS`. This is no longer the right thing to do, if one wants portable code that works with either traditional or GMP long integer arithmetic. First, one has to decide whether one wants to test if `NumBits(n)` is bounded by `NTL_ZZ_NBITS`, `NTL_SP_NBITS`, or `NTL_WSP_NBITS`. In the first case, `n.size() <= 1` is still the right way to test this. In the second case, write this as `n.SinglePrecision()`. In the third case, write this as `n.WideSinglePrecision()`. The routines `SinglePrecision` and `WideSinglePrecision` are new to NTL version 5.0.

Most "high level" applications that use NTL should not be affected by these changes to NTL's programming interface, and if they are, changing the programs should be quite easy.