Introduced primarily to help convert programs from the language Balsa to LARD, the mpint library provides an interface to the GNU gmp library to LARD.
The gmp library provides support for arithmetic and logical operations on arbitrarily large integers. Providing an interface to gmp from LARD has proved much easier than providing native bignum support written in either LARD or icode. Serious users are strongly urged to read the documentation for this library before making use of this library.
Arbitrary precision integers are represented by the type mpint:
mpint : type .
Values of this type are just pointers to GNU gmp mpz_t objects in the interpreter's memory space. The user must undertake their own store management on mpints as LARD has no support for garbage collection or any other sort of proper `object like' values for that matter. This form of explicit pointer management is somewhat different to the reference counting used by string library and is equally distasteful, I make no apologies.
Easy to manage systems making complete use of mpints can be constructed by wrapping the objects up in a new type, copying values on variable reads (by defining a replacement for read) and overloading the assignment operator. If all normal functions then consume (i.e. destroy) their arguments simple, if not particularly efficient, explicit store management can be achieved.
A quick example:
a : var(mpint) . a := mpint_init ; printmpint (a) ; mpint_clear (a)
Most functions with names starting with mpint_ are direct mappings of the gmp mpz_ functions into LARD functions. Here mpint_init combines allocation of space for an mpint and calling the gmp mpz_init function. So, mpint_init provides fresh mpints (which also happen to be initialised to 0). The call to printmpint prints the newly allocated mpint to standard output in decimal. Many of the integer I/O and string conversion functions are overloaded for use of mpints. A final call to mpint_clear surrenders the object to the store manager (== calls free(3)). No further use of the value in the variable a can be made after the call to mpint_clear unless a new value is assigned to it.
N.B. Assignment just copies the pointer to the underlying mpz_t. To copy an existing mpint into an uninitialised variable use the function mpint_copy or to copy a value from one mpint to an *initialised* mpint use mpint_set. Also note that although mpints are almost always passed by value they are pointers and so their underlying object can still be modified by the bodies of functions taking val arguments. Some example initialisations/copies:
b : var(mpint) . c : var(mpint) . d : var(mpint) . b := mpint_init ; /* A new mpint */ c := s2mpint ("4356") ; /* Make a new mpint with value 4356 */ d := mpint_copy (c) ; /* d need not be initialised */ mpint_set (c, b) ; /* c *must* be initialised (just like mpz_set) */
The complete set of initialisation and setting functions available is:
Returns a newly allocated mpint set to zero.
Dispose of the mpint arg. Any mpints stored in variables which point to the same mpz_t object as arg will now be invalid.
Copy the value from the initialised mpint src to the initialised mpint dst.
Like mpint_set except src is an int which is treated as an unsigned value.
As mpint_set_ui except src is treated as being signed.
Set initialised mpint dst to the decimal value in string src.
Make a copy of src and return it.
Print the mpint arg in decimal to stream file.
Read a newly allocated mpint (in decimal) from stream file.
fprintmpint to standard out.
fprintmpint in lower case hex.
Ditto to standard out
printmpint for overloading print.
The second group are overloaded versions of the operations:
unary -, +, -, *, /, mod, abs, min, max, not, and, or, <<, >>, bitsdiff, <, <=, =, !=, >=, >
These consume their mpint arguments to make constructing complicated expression easier. Overloadings are defined for operations purely on mpints and also from mixtures of mpint and int arguments.
Various integer <=> mpint and string <=> mpint functions are implemented. None of the functions consume their mpint arguments. Most of the string operations are overloadings of integer operations. For more flexibility user the mpint_ versions and the formatdata function:
Returns the bottom word of the given mpint as an int.
Ditto but reflect the sign of the given mpint.
i2mpint (i : val(int)) : expr(mpint),Reverse functions of mpint2i and mpint2si.
Convert the given strings to mpints. The strings are in decimal, hexadecimal, octal and binary respectively
Format the mpint value into a string using the format format. Use of the `!' flag to prevent the formatting advancing to the next argument and the use of bit extraction can be particularly useful here. e.g. "%!(3:0)mX,%!(7:4)mX" returns a string with two hex digits representing bit-field 3 to 0 and 7 to 4 separated by a comma.
Overloaded versions of the integer bit-field extraction operator mpint`[`range`]` (which consumes its mpint argument), the bit extraction operator mpint`[`int`]` (which doesn't) and the prefix bitmask, bitfield, setbit and signextend functions (which also don't consume their arguments) are provided. All bit indices and ranges are represented by ints and range(int)s respectively.
The mpint_cmp... functions return a value of type mpint_cmp_t instead of the constants -1, 0 and 1. Instead one of the symbolic constants cmp_less_than, cmp_equal and cmp_greater_than is returned. I suppose this more of an advantage in C where expressions like if (! mpz_cmp (a, b)) is the confusing mpint equality operation.
BTW. Mine's a pint.