Constant gmp_mpfr_sys::C::GMP::GMP_Basics[][src]

pub const GMP_Basics: ();

This constant is a place-holder for documentation; do not use it in code.


Next: , Previous: , Up: Top   [Index]

3 GMP Basics

Using functions, macros, data types, etc. not documented in this manual is strongly discouraged. If you do so your application is guaranteed to be incompatible with future versions of GMP.


Next: , Previous: , Up: GMP Basics   [Index]

3.1 Headers and Libraries

All declarations needed to use GMP are collected in the include file gmp.h. It is designed to work with both C and C++ compilers.

#include <gmp.h>

Note however that prototypes for GMP functions with FILE * parameters are only provided if <stdio.h> is included too.

#include <stdio.h>
#include <gmp.h>

Likewise <stdarg.h> is required for prototypes with va_list parameters, such as gmp_vprintf. And <obstack.h> for prototypes with struct obstack parameters, such as gmp_obstack_printf, when available.

All programs using GMP must link against the libgmp library. On a typical Unix-like system this can be done with ‘-lgmp’, for example

gcc myprogram.c -lgmp

GMP C++ functions are in a separate libgmpxx library. This is built and installed if C++ support has been enabled (see Build Options). For example,

g++ mycxxprog.cc -lgmpxx -lgmp

GMP is built using Libtool and an application can use that to link if desired, see GNU Libtool in GNU Libtool.

If GMP has been installed to a non-standard location then it may be necessary to use ‘-I’ and ‘-L’ compiler options to point to the right directories, and some sort of run-time path for a shared library.


3.2 Nomenclature and Types

In this manual, integer usually means a multiple precision integer, as defined by the GMP library. The C data type for such integers is mpz_t. Here are some examples of how to declare such integers:

mpz_t sum;
struct foo { mpz_t x, y; };
mpz_t vec[20];

Rational number means a multiple precision fraction. The C data type for these fractions is mpq_t. For example:

mpq_t quotient;

Floating point number or Float for short, is an arbitrary precision mantissa with a limited precision exponent. The C data type for such objects is mpf_t. For example:

mpf_t fp;

The floating point functions accept and return exponents in the C type mp_exp_t. Currently this is usually a long, but on some systems it’s an int for efficiency.

A limb means the part of a multi-precision number that fits in a single machine word. (We chose this word because a limb of the human body is analogous to a digit, only larger, and containing several digits.) Normally a limb is 32 or 64 bits. The C data type for a limb is mp_limb_t.

Counts of limbs of a multi-precision number represented in the C type mp_size_t. Currently this is normally a long, but on some systems it’s an int for efficiency, and on some systems it will be long long in the future.

Counts of bits of a multi-precision number are represented in the C type mp_bitcnt_t. Currently this is always an unsigned long, but on some systems it will be an unsigned long long in the future.

Random state means an algorithm selection and current state data. The C data type for such objects is gmp_randstate_t. For example:

gmp_randstate_t rstate;

Also, in general mp_bitcnt_t is used for bit counts and ranges, and size_t is used for byte or character counts.


3.3 Function Classes

There are six classes of functions in the GMP library:

  1. Functions for signed integer arithmetic, with names beginning with mpz_. The associated type is mpz_t. There are about 150 functions in this class. (see Integer Functions)
  2. Functions for rational number arithmetic, with names beginning with mpq_. The associated type is mpq_t. There are about 35 functions in this class, but the integer functions can be used for arithmetic on the numerator and denominator separately. (see Rational Number Functions)
  3. Functions for floating-point arithmetic, with names beginning with mpf_. The associated type is mpf_t. There are about 70 functions is this class. (see Floating-point Functions)
  4. Fast low-level functions that operate on natural numbers. These are used by the functions in the preceding groups, and you can also call them directly from very time-critical user programs. These functions’ names begin with mpn_. The associated type is array of mp_limb_t. There are about 60 (hard-to-use) functions in this class. (see Low-level Functions)
  5. Miscellaneous functions. Functions for setting up custom allocation and functions for generating random numbers. (see Custom Allocation, and see Random Number Functions)

3.4 Variable Conventions

GMP functions generally have output arguments before input arguments. This notation is by analogy with the assignment operator.

GMP lets you use the same variable for both input and output in one call. For example, the main function for integer multiplication, mpz_mul, can be used to square x and put the result back in x with

mpz_mul (x, x, x);

Before you can assign to a GMP variable, you need to initialize it by calling one of the special initialization functions. When you’re done with a variable, you need to clear it out, using one of the functions for that purpose. Which function to use depends on the type of variable. See the chapters on integer functions, rational number functions, and floating-point functions for details.

A variable should only be initialized once, or at least cleared between each initialization. After a variable has been initialized, it may be assigned to any number of times.

For efficiency reasons, avoid excessive initializing and clearing. In general, initialize near the start of a function and clear near the end. For example,

void
foo (void)
{
  mpz_t  n;
  int    i;
  mpz_init (n);
  for (i = 1; i < 100; i++)
    {
      mpz_mul (n, …);
      mpz_fdiv_q (n, …);
      …
    }
  mpz_clear (n);
}

GMP types like mpz_t are implemented as one-element arrays of certain structures. Declaring a variable creates an object with the fields GMP needs, but variables are normally manipulated by using the pointer to the object. For both behavior and efficiency reasons, it is discouraged to make copies of the GMP object itself (either directly or via aggregate objects containing such GMP objects). If copies are done, all of them must be used read-only; using a copy as the output of some function will invalidate all the other copies. Note that the actual fields in each mpz_t etc are for internal use only and should not be accessed directly by code that expects to be compatible with future GMP releases.


3.5 Parameter Conventions

When a GMP variable is used as a function parameter, it’s effectively a call-by-reference, meaning that when the function stores a value there it will change the original in the caller. Parameters which are input-only can be designated const to provoke a compiler error or warning on attempting to modify them.

When a function is going to return a GMP result, it should designate a parameter that it sets, like the library functions do. More than one value can be returned by having more than one output parameter, again like the library functions. A return of an mpz_t etc doesn’t return the object, only a pointer, and this is almost certainly not what’s wanted.

Here’s an example accepting an mpz_t parameter, doing a calculation, and storing the result to the indicated parameter.

void
foo (mpz_t result, const mpz_t param, unsigned long n)
{
  unsigned long  i;
  mpz_mul_ui (result, param, n);
  for (i = 1; i < n; i++)
    mpz_add_ui (result, result, i*7);
}
int
main (void)
{
  mpz_t  r, n;
  mpz_init (r);
  mpz_init_set_str (n, "123456", 0);
  foo (r, n, 20L);
  gmp_printf ("%Zd\n", r);
  return 0;
}

Our function foo works even if its caller passes the same variable for param and result, just like the library functions. But sometimes it’s tricky to make that work, and an application might not want to bother supporting that sort of thing.

Since GMP types are implemented as one-element arrays, using a GMP variable as a parameter passes a pointer to the object. Hence the call-by-reference.


Next: , Previous: , Up: GMP Basics   [Index]

3.6 Memory Management

The GMP types like mpz_t are small, containing only a couple of sizes, and pointers to allocated data. Once a variable is initialized, GMP takes care of all space allocation. Additional space is allocated whenever a variable doesn’t have enough.

mpz_t and mpq_t variables never reduce their allocated space. Normally this is the best policy, since it avoids frequent reallocation. Applications that need to return memory to the heap at some particular point can use mpz_realloc2, or clear variables no longer needed.

mpf_t variables, in the current implementation, use a fixed amount of space, determined by the chosen precision and allocated at initialization, so their size doesn’t change.

All memory is allocated using malloc and friends by default, but this can be changed, see Custom Allocation. Temporary memory on the stack is also used (via alloca), but this can be changed at build-time if desired, see Build Options.


3.7 Reentrancy

GMP is reentrant and thread-safe, with some exceptions:


3.8 Useful Macros and Constants

Global Constant: const int mp_bits_per_limb

The number of bits per limb.

Macro: __GNU_MP_VERSION
Macro: __GNU_MP_VERSION_MINOR
Macro: __GNU_MP_VERSION_PATCHLEVEL

The major and minor GMP version, and patch level, respectively, as integers. For GMP i.j, these numbers will be i, j, and 0, respectively. For GMP i.j.k, these numbers will be i, j, and k, respectively.

Global Constant: const char * const gmp_version

The GMP version number, as a null-terminated string, in the form “i.j.k”. This release is "6.2.0". Note that the format “i.j” was used, before version 4.3.0, when k was zero.

Macro: __GMP_CC
Macro: __GMP_CFLAGS

The compiler and compiler flags, respectively, used when compiling GMP, as strings.


3.9 Compatibility with older versions

This version of GMP is upwardly binary compatible with all 5.x, 4.x, and 3.x versions, and upwardly compatible at the source level with all 2.x versions, with the following exceptions.

There are a number of compatibility issues between GMP 1 and GMP 2 that of course also apply when porting applications from GMP 1 to GMP 5. Please see the GMP 2 manual for details.


3.10 Demonstration programs

The demos subdirectory has some sample programs using GMP. These aren’t built or installed, but there’s a Makefile with rules for them. For instance,

make pexpr
./pexpr 68^975+10

The following programs are provided

As an aside, consideration has been given at various times to some sort of expression evaluation within the main GMP library. Going beyond something minimal quickly leads to matters like user-defined functions, looping, fixnums for control variables, etc, which are considered outside the scope of GMP (much closer to language interpreters or compilers, See Language Bindings.) Something simple for program input convenience may yet be a possibility, a combination of the expr demo and the pexpr tree back-end perhaps. But for now the above evaluators are offered as illustrations.


Next: , Previous: , Up: GMP Basics   [Index]

3.11 Efficiency

Small Operands

On small operands, the time for function call overheads and memory allocation can be significant in comparison to actual calculation. This is unavoidable in a general purpose variable precision library, although GMP attempts to be as efficient as it can on both large and small operands.

Static Linking

On some CPUs, in particular the x86s, the static libgmp.a should be used for maximum speed, since the PIC code in the shared libgmp.so will have a small overhead on each function call and global data address. For many programs this will be insignificant, but for long calculations there’s a gain to be had.

Initializing and Clearing

Avoid excessive initializing and clearing of variables, since this can be quite time consuming, especially in comparison to otherwise fast operations like addition.

A language interpreter might want to keep a free list or stack of initialized variables ready for use. It should be possible to integrate something like that with a garbage collector too.

Reallocations

An mpz_t or mpq_t variable used to hold successively increasing values will have its memory repeatedly realloced, which could be quite slow or could fragment memory, depending on the C library. If an application can estimate the final size then mpz_init2 or mpz_realloc2 can be called to allocate the necessary space from the beginning (see Initializing Integers).

It doesn’t matter if a size set with mpz_init2 or mpz_realloc2 is too small, since all functions will do a further reallocation if necessary. Badly overestimating memory required will waste space though.

2exp Functions

It’s up to an application to call functions like mpz_mul_2exp when appropriate. General purpose functions like mpz_mul make no attempt to identify powers of two or other special forms, because such inputs will usually be very rare and testing every time would be wasteful.

ui and si Functions

The ui functions and the small number of si functions exist for convenience and should be used where applicable. But if for example an mpz_t contains a value that fits in an unsigned long there’s no need extract it and call a ui function, just use the regular mpz function.

In-Place Operations

mpz_abs, mpq_abs, mpf_abs, mpz_neg, mpq_neg and mpf_neg are fast when used for in-place operations like mpz_abs(x,x), since in the current implementation only a single field of x needs changing. On suitable compilers (GCC for instance) this is inlined too.

mpz_add_ui, mpz_sub_ui, mpf_add_ui and mpf_sub_ui benefit from an in-place operation like mpz_add_ui(x,x,y), since usually only one or two limbs of x will need to be changed. The same applies to the full precision mpz_add etc if y is small. If y is big then cache locality may be helped, but that’s all.

mpz_mul is currently the opposite, a separate destination is slightly better. A call like mpz_mul(x,x,y) will, unless y is only one limb, make a temporary copy of x before forming the result. Normally that copying will only be a tiny fraction of the time for the multiply, so this is not a particularly important consideration.

mpz_set, mpq_set, mpq_set_num, mpf_set, etc, make no attempt to recognise a copy of something to itself, so a call like mpz_set(x,x) will be wasteful. Naturally that would never be written deliberately, but if it might arise from two pointers to the same object then a test to avoid it might be desirable.

if (x != y)
  mpz_set (x, y);

Note that it’s never worth introducing extra mpz_set calls just to get in-place operations. If a result should go to a particular variable then just direct it there and let GMP take care of data movement.

Divisibility Testing (Small Integers)

mpz_divisible_ui_p and mpz_congruent_ui_p are the best functions for testing whether an mpz_t is divisible by an individual small integer. They use an algorithm which is faster than mpz_tdiv_ui, but which gives no useful information about the actual remainder, only whether it’s zero (or a particular value).

However when testing divisibility by several small integers, it’s best to take a remainder modulo their product, to save multi-precision operations. For instance to test whether a number is divisible by any of 23, 29 or 31 take a remainder modulo 23*29*31 = 20677 and then test that.

The division functions like mpz_tdiv_q_ui which give a quotient as well as a remainder are generally a little slower than the remainder-only functions like mpz_tdiv_ui. If the quotient is only rarely wanted then it’s probably best to just take a remainder and then go back and calculate the quotient if and when it’s wanted (mpz_divexact_ui can be used if the remainder is zero).

Rational Arithmetic

The mpq functions operate on mpq_t values with no common factors in the numerator and denominator. Common factors are checked-for and cast out as necessary. In general, cancelling factors every time is the best approach since it minimizes the sizes for subsequent operations.

However, applications that know something about the factorization of the values they’re working with might be able to avoid some of the GCDs used for canonicalization, or swap them for divisions. For example when multiplying by a prime it’s enough to check for factors of it in the denominator instead of doing a full GCD. Or when forming a big product it might be known that very little cancellation will be possible, and so canonicalization can be left to the end.

The mpq_numref and mpq_denref macros give access to the numerator and denominator to do things outside the scope of the supplied mpq functions. See Applying Integer Functions.

The canonical form for rationals allows mixed-type mpq_t and integer additions or subtractions to be done directly with multiples of the denominator. This will be somewhat faster than mpq_add. For example,

/* mpq increment */
mpz_add (mpq_numref(q), mpq_numref(q), mpq_denref(q));
/* mpq += unsigned long */
mpz_addmul_ui (mpq_numref(q), mpq_denref(q), 123UL);
/* mpq -= mpz */
mpz_submul (mpq_numref(q), mpq_denref(q), z);
Number Sequences

Functions like mpz_fac_ui, mpz_fib_ui and mpz_bin_uiui are designed for calculating isolated values. If a range of values is wanted it’s probably best to call to get a starting point and iterate from there.

Text Input/Output

Hexadecimal or octal are suggested for input or output in text form. Power-of-2 bases like these can be converted much more efficiently than other bases, like decimal. For big numbers there’s usually nothing of particular interest to be seen in the digits, so the base doesn’t matter much.

Maybe we can hope octal will one day become the normal base for everyday use, as proposed by King Charles XII of Sweden and later reformers.


Next: , Previous: , Up: GMP Basics   [Index]

3.12 Debugging

Stack Overflow

Depending on the system, a segmentation violation or bus error might be the only indication of stack overflow. See ‘--enable-alloca’ choices in Build Options, for how to address this.

In new enough versions of GCC, ‘-fstack-check’ may be able to ensure an overflow is recognised by the system before too much damage is done, or ‘-fstack-limit-symbol’ or ‘-fstack-limit-register’ may be able to add checking if the system itself doesn’t do any (see Options for Code Generation in Using the GNU Compiler Collection (GCC)). These options must be added to the ‘CFLAGS’ used in the GMP build (see Build Options), adding them just to an application will have no effect. Note also they’re a slowdown, adding overhead to each function call and each stack allocation.

Heap Problems

The most likely cause of application problems with GMP is heap corruption. Failing to init GMP variables will have unpredictable effects, and corruption arising elsewhere in a program may well affect GMP. Initializing GMP variables more than once or failing to clear them will cause memory leaks.

In all such cases a malloc debugger is recommended. On a GNU or BSD system the standard C library malloc has some diagnostic facilities, see Allocation Debugging in The GNU C Library Reference Manual, or ‘man 3 malloc’. Other possibilities, in no particular order, include

The GMP default allocation routines in memory.c also have a simple sentinel scheme which can be enabled with #define DEBUG in that file. This is mainly designed for detecting buffer overruns during GMP development, but might find other uses.

Stack Backtraces

On some systems the compiler options GMP uses by default can interfere with debugging. In particular on x86 and 68k systems ‘-fomit-frame-pointer’ is used and this generally inhibits stack backtracing. Recompiling without such options may help while debugging, though the usual caveats about it potentially moving a memory problem or hiding a compiler bug will apply.

GDB, the GNU Debugger

A sample .gdbinit is included in the distribution, showing how to call some undocumented dump functions to print GMP variables from within GDB. Note that these functions shouldn’t be used in final application code since they’re undocumented and may be subject to incompatible changes in future versions of GMP.

Source File Paths

GMP has multiple source files with the same name, in different directories. For example mpz, mpq and mpf each have an init.c. If the debugger can’t already determine the right one it may help to build with absolute paths on each C file. One way to do that is to use a separate object directory with an absolute path to the source directory.

cd /my/build/dir
/my/source/dir/gmp-6.2.0/configure

This works via VPATH, and might require GNU make. Alternately it might be possible to change the .c.lo rules appropriately.

Assertion Checking

The build option --enable-assert is available to add some consistency checks to the library (see Build Options). These are likely to be of limited value to most applications. Assertion failures are just as likely to indicate memory corruption as a library or compiler bug.

Applications using the low-level mpn functions, however, will benefit from --enable-assert since it adds checks on the parameters of most such functions, many of which have subtle restrictions on their usage. Note however that only the generic C code has checks, not the assembly code, so --disable-assembly should be used for maximum checking.

Temporary Memory Checking

The build option --enable-alloca=debug arranges that each block of temporary memory in GMP is allocated with a separate call to malloc (or the allocation function set with mp_set_memory_functions).

This can help a malloc debugger detect accesses outside the intended bounds, or detect memory not released. In a normal build, on the other hand, temporary memory is allocated in blocks which GMP divides up for its own use, or may be allocated with a compiler builtin alloca which will go nowhere near any malloc debugger hooks.

Maximum Debuggability

To summarize the above, a GMP build for maximum debuggability would be

./configure --disable-shared --enable-assert \
  --enable-alloca=debug --disable-assembly CFLAGS=-g

For C++, add ‘--enable-cxx CXXFLAGS=-g’.

Checker

The GCC checker (https://savannah.nongnu.org/projects/checker/) can be used with GMP. It contains a stub library which means GMP applications compiled with checker can use a normal GMP build.

A build of GMP with checking within GMP itself can be made. This will run very very slowly. On GNU/Linux for example,

./configure --disable-assembly CC=checkergcc

--disable-assembly must be used, since the GMP assembly code doesn’t support the checking scheme. The GMP C++ features cannot be used, since current versions of checker (0.9.9.1) don’t yet support the standard C++ library.

Valgrind

Valgrind (http://valgrind.org/) is a memory checker for x86, ARM, MIPS, PowerPC, and S/390. It translates and emulates machine instructions to do strong checks for uninitialized data (at the level of individual bits), memory accesses through bad pointers, and memory leaks.

Valgrind does not always support every possible instruction, in particular ones recently added to an ISA. Valgrind might therefore be incompatible with a recent GMP or even a less recent GMP which is compiled using a recent GCC.

GMP’s assembly code sometimes promotes a read of the limbs to some larger size, for efficiency. GMP will do this even at the start and end of a multilimb operand, using naturally aligned operations on the larger type. This may lead to benign reads outside of allocated areas, triggering complaints from Valgrind. Valgrind’s option ‘--partial-loads-ok=yes’ should help.

Other Problems

Any suspected bug in GMP itself should be isolated to make sure it’s not an application problem, see Reporting Bugs.


Next: , Previous: , Up: GMP Basics   [Index]

3.13 Profiling

Running a program under a profiler is a good way to find where it’s spending most time and where improvements can be best sought. The profiling choices for a GMP build are as follows.

--disable-profiling

The default is to add nothing special for profiling.

It should be possible to just compile the mainline of a program with -p and use prof to get a profile consisting of timer-based sampling of the program counter. Most of the GMP assembly code has the necessary symbol information.

This approach has the advantage of minimizing interference with normal program operation, but on most systems the resolution of the sampling is quite low (10 milliseconds for instance), requiring long runs to get accurate information.

--enable-profiling=prof

Build with support for the system prof, which means ‘-p’ added to the ‘CFLAGS’.

This provides call counting in addition to program counter sampling, which allows the most frequently called routines to be identified, and an average time spent in each routine to be determined.

The x86 assembly code has support for this option, but on other processors the assembly routines will be as if compiled without ‘-p’ and therefore won’t appear in the call counts.

On some systems, such as GNU/Linux, ‘-p’ in fact means ‘-pg’ and in this case ‘--enable-profiling=gprof’ described below should be used instead.

--enable-profiling=gprof

Build with support for gprof, which means ‘-pg’ added to the ‘CFLAGS’.

This provides call graph construction in addition to call counting and program counter sampling, which makes it possible to count calls coming from different locations. For example the number of calls to mpn_mul from mpz_mul versus the number from mpf_mul. The program counter sampling is still flat though, so only a total time in mpn_mul would be accumulated, not a separate amount for each call site.

The x86 assembly code has support for this option, but on other processors the assembly routines will be as if compiled without ‘-pg’ and therefore not be included in the call counts.

On x86 and m68k systems ‘-pg’ and ‘-fomit-frame-pointer’ are incompatible, so the latter is omitted from the default flags in that case, which might result in poorer code generation.

Incidentally, it should be possible to use the gprof program with a plain ‘--enable-profiling=prof’ build. But in that case only the ‘gprof -p’ flat profile and call counts can be expected to be valid, not the ‘gprof -q’ call graph.

--enable-profiling=instrument

Build with the GCC option ‘-finstrument-functions’ added to the ‘CFLAGS’ (see Options for Code Generation in Using the GNU Compiler Collection (GCC)).

This inserts special instrumenting calls at the start and end of each function, allowing exact timing and full call graph construction.

This instrumenting is not normally a standard system feature and will require support from an external library, such as

This should be included in ‘LIBS’ during the GMP configure so that test programs will link. For example,

./configure --enable-profiling=instrument LIBS=-lfc

On a GNU system the C library provides dummy instrumenting functions, so programs compiled with this option will link. In this case it’s only necessary to ensure the correct library is added when linking an application.

The x86 assembly code supports this option, but on other processors the assembly routines will be as if compiled without ‘-finstrument-functions’ meaning time spent in them will effectively be attributed to their caller.


Next: , Previous: , Up: GMP Basics   [Index]

3.14 Autoconf

Autoconf based applications can easily check whether GMP is installed. The only thing to be noted is that GMP library symbols from version 3 onwards have prefixes like __gmpz. The following therefore would be a simple test,

AC_CHECK_LIB(gmp, __gmpz_init)

This just uses the default AC_CHECK_LIB actions for found or not found, but an application that must have GMP would want to generate an error if not found. For example,

AC_CHECK_LIB(gmp, __gmpz_init, ,
  [AC_MSG_ERROR([GNU MP not found, see https://gmplib.org/])])

If functions added in some particular version of GMP are required, then one of those can be used when checking. For example mpz_mul_si was added in GMP 3.1,

AC_CHECK_LIB(gmp, __gmpz_mul_si, ,
  [AC_MSG_ERROR(
  [GNU MP not found, or not 3.1 or up, see https://gmplib.org/])])

An alternative would be to test the version number in gmp.h using say AC_EGREP_CPP. That would make it possible to test the exact version, if some particular sub-minor release is known to be necessary.

In general it’s recommended that applications should simply demand a new enough GMP rather than trying to provide supplements for features not available in past versions.

Occasionally an application will need or want to know the size of a type at configuration or preprocessing time, not just with sizeof in the code. This can be done in the normal way with mp_limb_t etc, but GMP 4.0 or up is best for this, since prior versions needed certain ‘-D’ defines on systems using a long long limb. The following would suit Autoconf 2.50 or up,

AC_CHECK_SIZEOF(mp_limb_t, , [#include <gmp.h>])

Previous: , Up: GMP Basics   [Index]

3.15 Emacs

C-h C-i (info-lookup-symbol) is a good way to find documentation on C functions while editing (see Info Documentation Lookup in The Emacs Editor).

The GMP manual can be included in such lookups by putting the following in your .emacs,

(eval-after-load "info-look"
  '(let ((mode-value (assoc 'c-mode (assoc 'symbol info-lookup-alist))))
     (setcar (nthcdr 3 mode-value)
             (cons '("(gmp)Function Index" nil "^ -.* " "\\>")
                   (nth 3 mode-value)))))

Previous: , Up: GMP Basics   [Index]