The reason for this comes from the implementation of mpn
. Specifically, if you're mathematically inclined you'll realise N is the set of natural numbers (1,2,3,4...) whereas Z is the set of integers (...,-2,-1,0,1,2,...).
Implementing a bignum library for Z is equivalent to doing so for N and taking into account some special rules for sign operations, i.e. keeping track of whether you need to do an addition or a subtraction and what the result is.
Now, as for how a bignum library is implemented... here's a line to give you a clue:
typedef unsigned int mp_limb_t;
typedef mp_limb_t * mp_ptr;
And now let's look at a function signature operating on that:
__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t));
Basically, what it comes down to is that a "limb" is an integer field representing the bits of a number and the whole number is represented as a huge array. The clever part is that gmp does all this in a very efficient, well optimised manner.
Anyway, back to the discussion. Basically, the only way to pass arrays around in C is, as you know, to pass pointers to those arrays which effectively enables pass by reference. Now, in order to keep track of what's going on, two types are defined, a mp_ptr
which is an array of mp_limb_t
big enough to store your number, and mp_srcptr
which is a const version of that, so that you cannot accidentally alter the bits of the source bignums on what you are operating. The basic idea is that most of the functions follow this pattern:
func(ptr output, src in1, src in2)
etc. Thus, I suspect mpz_*
functions follow this convention simply to be consistent and it is because that is how the authors are thinking.
Short version: Because of how you have to implement a bignum lib, this is necessary.