The MacLaurin Computing Library


This library is intended to help large computations rather then performing individual calculations (in which case you should use a Computer Algebra System like GNU Maxima). Of course it is as well intended to be linked with any piece of code that may need it. In order to use it, you must first compile and install the GNU MP Bignum library on your computer.

The library provides the four arithmetic operations on functions of any kind, represented by the coefficients of their MacLaurin series expansion. The computation returns exact results, but remember that for obvious reasons, the functions always end with some O(xk) term: f(x)=a_0 + a_1 x + a_2 x^2 + a_3 x^3 + ... + a_{k-1} x^{k-1} + a_k x^k + O(x^{k+1}) For various reasons, the coefficients have been chosen to be rationals. They are implemented with the mpq_t type of GMP.

The computation is intended to be quick, since speed was a great issue when writing the code. More precisely, the library should almost often be quicker than a Computer Algebra System; it should be much quicker when handling functions with no well-known properties. Of course if you want to compute the division e3x/e2x you can't expect the library to be as efficient as a CAS, since it really doesn't care about noticing that e3x/e2x = ex before computing the coefficients. On the other hand, operations leading to a result that a CAS wouldn't easely simplify will very probably be quicker with the MacLaurin library. For more informations concerning the complexity of the algorithm, have a look at the F.A.Q..

The functions operate on a type called ml_t through a pointer. Thus define the variables with ml_t a,b,c; in your piece of code, and then call the functions with &a, &b, &c like: ml_init(&,12); ml_init(&b,12); ml_init(&c,12); We follow here the GMP convention: the first argument of the function will be the result of the computation. Note that when macros expand to some expression, it has to be called with a variable (and not a pointer).

The degree of a ml_t variable is the degree of the highest significant coefficient. Thus 1 + x - 2 x2 + O(x3) has 2 for its degree. This is an important issue when using the functions, since the arrays of coefficient for assigning the values must contain (at least) k+1 values for a degree k. Results are unpredictable when a function uses variables with different degrees (false result, segmentation fault, etc.)

Each ml_t variable has to be initialized before being used. Except for some trivial programs, each variable should rather be cleared after being used for the last time.

List of available functions (and macros)

ml_degree(ml_t a);

expand as the degree (with the highest significant coefficient) of a; this is a macro: be carefull to put the variable in the argument (and not a pointer to it).

ml_nth_get(ml_t a, unsigned int n);

expand as the mpq_t coefficient of degree n in a; this is a macro: be carefull to put the variable in the argument (and not a pointer to it).

void ml_init(ml_t *a, unsigned int n);

initialize a with degree n without assigning its value.

void ml_clear(ml_t *a);

free the memory used by a; the variable has to be initialized again if it has to be used again (but of course the current value will be lost).

void ml_init_set(ml_t *a, ml_t *d);

initialize a and make a copy of d.

void ml_init_set_q(ml_t *a, unsigned int n, mpq_t *d);

initialize a with degree n and assign its value by taking the n+1 mpq_t coefficients in the array d.

void ml_init_set_z(ml_t *a, unsigned int n, mpz_t *d);

initialize a with degree n and assign its value by taking the n+1 mpz_t coefficients in the array d.

void ml_init_set_ui(ml_t *a, unsigned int n, unsigned int *d);

initialize a with degree n and assign its value by taking the n+1 unsigned int coefficients in the array d.

void ml_init_set_si(ml_t *a, unsigned int n, signed int *d);

initialize a with degree n and assign its value by taking the n+1 signed int coefficients in the array d.

void ml_set(ml_t *a, ml_t *d);

void ml_set_q(ml_t *a, mpq_t *d);

void ml_set_z(ml_t *a, mpz_t *d);

void ml_set_ui(ml_t *a, unsigned int *d);

void ml_set_si(ml_t *a, signed int *d);

assign the values of a (already initialized) by taking enough coefficients (one more than its degree) in the array d; the function may be chosen according to the desired type of the coefficients.

void ml_init_set_diff_q(ml_t *a, unsigned int n, mpq_t *d);

void ml_init_set_diff_z(ml_t *a, unsigned int n, mpz_t *d):

void ml_init_set_diff_ui(ml_t *a, unsigned int n, unsigned int *d);

void ml_init_set_diff_si(ml_t *a, unsigned int n, signed int *d);

void ml_set_diff_q(ml_t *a, mpq_t *d);

void ml_set_diff_z(ml_t *a, mpz_t *d);

void ml_set_diff_ui(ml_t *a, unsigned int *d);

void ml_set_diff_si(ml_t *a, signed int *d);

these functions are similar to the previous ones, except that instead of directly assigning the coefficients of the MacLaurin series expansion, the array d provides rather the vector of successive derivates evaluated at 0. Thus assignation will be simpler in some cases: ex will be defined with {1,1,1,1,1,1} rather than with {1,1,1/2,1/6,1/24,1/120}.

void ml_set_cf(ml_t *res, const unsigned int n, ml_t *a, ml_t *b);

put in res the MacLaurin series expansion of the continued fraction with exactly n partial numerators and denominators b0(x)/(a0(x)+b1(x)/(a1(x)+b2(x)/(a2(x)+... with a and b being arrays of ml_t.

void ml_print(ml_t *a, char v, char c);

print the MacLaurin series a by using v for the variable (usually 'x' or 'z') and c for the multiplication symbol (if you use '*' the output will be readable by other software like Pari/GP; if you want a nice output for human eyes you may like to use ' ' or '\0' if you don't want any separation between the coefficient and the variable; any exotic choice is acceptable like '.').

void ml_add(ml_t *res, ml_t *a, ml_t *b);

void ml_neg(ml_t *, ml_t *);

void ml_sub(ml_t *res, ml_t *a, ml_t *b);

void ml_mul(ml_t *res, ml_t *a, ml_t *b);

void ml_inv0(ml_t *res, ml_t *in);

void ml_div0(ml_t *res, ml_t *a, ml_t *b);

void ml_inv(ml_t *res, ml_t *in);

void ml_div(ml_t *res, ml_t *a, ml_t *b);

these five functions provide the arithetic operations: addition, opposite, substraction, multiplication, inversion, division. Be very carefull since the two functions ml_inv0 and ml_div0 require the output variable to be different from the denominator in or b (but these functions are more efficient in that case).

void ml_expand_gf(ml_t *dest, signed int *num, unsigned int num_deg, signed int *den, unsigned int den_deg);

This function expands the generating function (being given as two arrays of signed integers, one for the numerator and one for the denominator); coefficient of degree 0 in the denominator must be different from 0. Of course this funtion merely performs a division and the same result could be found with the ml_div function, but this function is very efficient when many coefficients have to be computed from a generating function with relatively small degrees in the numerator and in the denominator.

Valid XHTML Valid CSS