     Genprec has been revised in late 1999 so that common arithmetical
operations such as =,+,-,*, and / can now be used as they would be in
C/C++, fortran, or basic.  gnlindex.cpp is a genprec code with a basic
code between /* */ which shows how similar those two codes are. The
examples offer numerous illustrations of the new overloaded operators.
One should print out the source codes and read them as the the examples
execute.  There are comments in the source codes which are not printed
to the screen.  Without those comments, what is printed on the screen
is less intelligible than it might be.  Perhaps the first example
which one should study, compile, and run is genpdex2.cc and the
second would be cgenpdex.cc.

     The elementary transcendental functions are also overloaded
so that one can write
                   a = sin(b) + sin(c);
for example.  
    
     A list of all genprec functions appears in the appendix
at the end.

     The quantity "z" no longer plays the role that it formerly
did (its former role is explained in manual.txt).  If one wants
to add a+b+c+d for example and store the result in e one writes
                      e=a+b+c+d;
The complexity allowed is very great, as the examples illustrate,
but there is a limit (which I do not know exactly) on how complex
the statements can be (overly complex expressions make the source
file a mess anyway).

     Now, all genprec routines which have an output (even the linear
system solvers, the polynomial solvers, operations with series and
operations with Pade approximants) have an output whose name is
to be assigned by the user.  One writes for example
                roots<solvpoly(n,a);
where "roots" is the array in in which the n roots of the n-th
degree polynomial a will be stored.  The user can use any name
desired in place of "roots".  One writes
                solution<solvlinear(n,m,r);
where "solution" is the solution of the nxn system mx=r.  "solution",
m, and r can be replaced by any names declared by the user.
The output of the Pade approximant routines is two polynomials, the
numerator and the denominator; how this is handled is described 
below.

     Note the occurrence of the operator < indicating that the
output of one of the more advanced functions in genprec is moving
to the array named on the left of <. (This array must be declared by
the user, of course).

     There are routines for printing, writing variables and
1-D (one dimensional) and 2-D arrays to a disk file and reading
them back from the disk file in which they are stored.  There
are routines for inputting lengthy multiple precision floating
data.  There are routines for comparing general precision
numbers.  The compare routine returns character strings "left
largest", "right largest", or "equal" referring to the two
arguments of the compare function, whose output may be given
any name desired, for example

              which=compare(a,b); 
    
     Now, there is no complicated "tree" for including the genprec
package. The "tree" has only three elements:

           #include "genprec.h" for ordinary real arithmetic
             or "genpnoas.sem"  including the elementary
                                transcendental functions
           #include "cgenprec.h" for complex arithmetic
                                including the elementary
                                transcendental functions
           #include "apps.h"    this includes the                     
                                linear system solvers and
                                everything else.

The reason (other than simplicity) is that when it comes to solving
polynomials, the boundary between real and complex arithmetic becomes
blurred because polynomials with real coefficients have complex roots.
As before, if one element of the "tree" is included, the elements
above it must be included.

     There are now only three genprec classes which the user will use,
namely, realmp, complexmp, (these are like "double" in
C/C++, except that the user specifies the precision desired), and
Pade. Arrays are declared as

   realmp m[zmaxsizepad][zmaxsizepad],r[zmaxsizepad];
   realmp solution[zmaxsizepad];

in the case of the problem mx=r referred to above, or, in the case
of complex arithmetic

   complexmp m[cmaxsizepad][cmaxsizepad],r[cmaxsizepad];
   complexmp solution[cmaxsizepad];

Pade approximants have to be treated a little differently from other
arrays because they have an output which is two polynomials.
In declaring a Pade approximant one writes

              real:           or          complex:
      pademp d;                   cpademp d;
      realmp num[zmaxsizepad];    complexmp num[zmaxsizepad];
      realmp den[zmaxsizepad];    complexmp den[zmaxsizepad];

where  the names of padeapproximant, its numerator, and denominator
(d,num,den above) are whatever the user wants.  In the code one
would write (see Appendix)

              real:           or          complex:
      d<padeapprox(m,n,a);        d<cpadeapprox(m,n,c);
      num<extractnum(m,d);        num<cextractnum(m,d);
      den<extractden(n,d);        den<cextractden(n,d);

The padded allocations are calculated by genprec from zmaxsize
and cmaxsize specified by the user.
     
     The opening lines begin as before. One includes whatever
parts of the C++ language one wishes, perhaps

#include <iostream.h>    //these four files standard for GENPREC
#include <stdlib.h>     //abs (absolute value)
#include <math.h>       //log,sqrt,etc (not mp, of course)
#include <time.h>       //use when timing (benchmarking)

      Then the precision is declared
as before:

const int precision=8; //means 32 significant figures, for example
const int precision=125;  //means 500 significant figures (I do
                       //this in fairly complicated problems
                       //and I have only 128mb of RAM.
const int precision=2500;  //means 10000 significant figures
                        //(amuse your friends by calculation pi,
                        //but not much else: try pi^2).

Then one must declare zmaxsize and cmaxsize (the sizes of the
largest real and complex arrays,respectively, which one will
deal with)

const int zmaxsize=10;  //perhaps
const int cmaxsize=0;   //If one has no complex arrays
                        //or perhaps
const int cmaxsize=10;  //otherwise

Then  one must include genprec and other elements of the "tree"
as desired.

At the beginning of main(), if one plans to use trigonometric
functions or log and exp functions, one must run

  zsuppi();        //this has to be run to do sin,cos,etc.
  zsupe();         //for log and exp functions
  zsuplogsp();     //     ditto

These store pi to more significant figures than precision requires
and stores them internally so that they do not have to be recalculated
over and over again.

  zpi=pi_mp();

will store the internally stored pi in zpi (or whatever else the user
may call pi) to the precision set by the user for later use.  The
same holds for the base of natural logarithms

 ze=e_mp();

where ze is whatever the user wishes to call the base of natural
logarithms.

The new package is completely backward consistent with the old
one in the sense that any code written for the old package will
still compile and run (perhaps with slight changes).  There are
examples to illustrate this remark in the genprec package.  Some
old codes such as the example cgenpdex.cpp compile and run without
modification.  Others, such as seresdx2.cpp have to include the new
files genprec.h, cgenprec.h, and apps.h rather than including what
was included previously. Also, precision, zmaxsize, and cmaxsize have
to be declared const int rather than int. The modifications necessary
to make it compile and run are marked.  

Some of what is contained in the old manuals
manual.txt and manuald.txt is still relevant and all of it is
still correct although a lot of it is out of date.

Note:  Some assembly language is used in the genprec package.
       The assembly language is appropriate for the Intel 486
architecture, which allows the assembly language commands
adc,mul,and div.  Unfortunately, when Intel changes to a
64 bit architecture (the so-called merced, which is really the
alpha architecture), these commands will be dropped (they
will have to be emulated, and it is not certain how that
will play out).
       There is a version of genprec which does not use
assembly language, but it is much slower (factor 4 as precision
becomes very large but a factor 3 for 512 significant figures
and less for lower precision) than the version with
assembly language.  To use it, include genpnoas.sem at the
top of your codes rather than genprec.h.
   
       The compilers with which genprec.h will work are:

    1) the C/C++ compiler in the Delorie port of gnu to DOS
       (djgpp) available free at www.delorie.com (a really great
       compiler which also comes with Charles W. Sanders
       memory manager which allows access to 128 mb of ram,
       and probably 900 mb by now, without swapping).
       Swapping slows things down much too much to make
       real general precision calculations possible.
    2) the Linux C/C++ compilers.  These allow access
       of up to 900 mb of ram (or however many) by typing
         linux mem=128mb (or however much memory you have)
       at the linux boot prompt.  They are great compilers.

       genpnoas.sem should work with any compiler on any machine.


Important note re Linux.  There is a line
                   #include "malloc.c"
at the very top of the file genprecd.h which one must remove
or comment out (// #include "malloc.c").  malloc.c refers to
the memory management in the Delorie port of gnu to DOS.  It
is probably automatically a part of djgpp by now and so it is
probably no longer necessary to include it explicitly when working
with djgpp, but in the version of the Delorie port which exists on
my machine I have to include it explicitly.

    3) any compiler compatible with 1 or 2.
The Watcom compiler, a great compiler now defunct, used a
different interface with assembly language.  I have stopped
worrying about making genprec work with the Watcom compiler
because the gnu compilers and the Linux compilers are better
and because Watcom is no longer supported by anyone.


                       Appendix

PRINTING: printmp(a); prints the realmp or complexmp number a.

It is not likely that one will actually want to look at the results
of calculations to (say) 200 significant figures even if such
precision is necessary in the course of a calculation.  In the
end, one may want to make a simple graph or table.  To this end,
there is a provision for converting genprec numbers to ordinary
float numbers:
               h=zconmptof(a);
where the declaration are float h; and realmp a;
For complex numbers,
               hr=zconmptof(realpartof(a));
               hi=zconmptof(imaginarypartof(a));
where the declarations are float hr,hi; and complexmp a; 

FILE OPERATIONS: Provision is made for writing realmp and complexmp
                 numbers, and 1-dimensional and 2-dimensional arrays
to a file named by the user and reading such data back from the file.

writetofile(realmp x,"filename")
readfromfile(realmp,"filename") 
write1Darraytofile(realmp x[zmaxsizepad], "filename")
read1Darrayfromfile(realmp x[zmaxsizepad], "filename")
write2Darraytofile(realmp x[zmaxsizepad][zmaxsizepad],"filename")
read2Darrayfromfile(realmp x[zmaxsizepad][zmaxsizepad],"filename") 
cwritetofile(complexmp z,"filename")               //37
creadfromfile(complexmp z,"filename")              //38
cwrite1Darraytofile(complexmp z[cmaxsizepad], "filename")    //39
cread1Darrayfromfile(complexmp z[cmaxsizepad], "filename")   //40
cwrite2Darraytofile(complexmp z[cmaxsizepad][cmaxsizepad],"filename") //41
cread2Darrayfromfile(complexmp z[cmaxsizepad][cmaxsizepad],"filename") //42

For higher dimensional arrays, one will have to find the above files
in overload.new or overload.cnu and generalize what is done there
to more dimensions.  genprec is "open" in the same sense as Linux
and one can change the "kernel" (that is, the source code) in any
way one wants.

INPUTTING DATA TO GENPREC:  It is anticipated that most, if not
                            all, input to a genprec calculation
will be integers or simple functions of integers such as 
fractions (such as 2/3 for example) or one of the elementary transcen-
dental functions of integers (such as sin(j*pi/k) or exp(i j*pi/k), where
j runs from 0 to k, for example).  The reason is that there is
hardly ever any point in doing general precision calculations when
the input data is not known to the precision with which is planned
to carry out the calculation.  However, in spite of that, provision
is made to convert data to genprec numbers.  For example, if x
is a realmp number, x=3.1415926E00 is allowed.  There is a
special variable zinput in which one may enter any number
       zinput[precision+1]=2; if the number is positive
                           0; if the number is negative
       zinput[precision]  =3141;
       zinput[precision-1]=5926; and so on four digits at a time
           .
           . //as many entries as one has the patience to type
           .
       until one reaches the last entry
       zinput[0]=1; which is the power of ten, reading the input as
                    .3141 5926, by which the number must be multiplied
                    (1 in the case of pi=.31415926E01).
Examples of this method may be found in example.cc.  

ARITHMETIC OPERATIONS:

c = a, where c is a realmp number.

   a can be an integer.  c=1 converts the integer one to a
                         realmp number and stores the result in c.
   a can be a float number.  c=1.5E00 converts 1.5E00 to a real
                             mp number and store the result in c.
   a can be a realmp number.

c = a, where c is a complex mp number.

   a can be a complex integer.  c=cinttomp(1,2) converts 1+2i
                             into a complexmp number and stores
                             the result in c.
   a can be a complexmp number.

a + b, a - b  where a or b is a realmp number.

   The other can be an integer or a realmp number.

Aside: one may well wonder why the other cannot be a real float
       number.  It is because, that while one can overload
       operator+ so that it adds int+realmp (for instance)
       or adds float+realmp, but if one tries to do both (that is
       int+realmp and float+realmp) and writes
                             c = 4 + b
       the compiler will report that this statement is ambiguous.
       Apparently, it doesn't know whether 4 is an integer or float.
       It seems to me that float numbers should always have their
       exponent (as in 4.0E00) but, alas, that is not the case.
       Therefore, in the float case, no operator other than
       operator= (as in c=4 or c=4.0E00) which, apparently, does
       not lead to ambiguities, is overloaded.

       If it is desired to use floats, write
                    c= floattomp(4.0E00) + b
       (do not omit the exponent E) which converts 4.0E00 to a realmp
       number before it is added to b. This applies to -,*,/, and ^
       as well.

       Strangely enough, c=b/4 works when operator/ is overloaded
       for both signed and unsigned integers in the denominator.
       That is to say, the compiler seems to handle the types
       int and unsigned int (except for occasionally not knowing
       whether 0 is int or unsigned int--if you run across this
       problem declare int thatzero=0 or unsigned int thatzero=0
       and put thatzero where you had 0 before).  Thus when I refer
       to "integer" I mean both types (int and unsigned int).
end of aside.
       
a + b, a - b where a or b is a complexmp number.

   The other can be a complexmp number, an integer, or a realmp number.
   If it is desired that one be a complex integer, use
   cinttomp(1,2) + b to add 1+2i to b, for example, or
   use cfloattomp(1.5E00,2.5E00) + b to add 1.5+2.5i to b,
   for example.

c = a1 +/- a2 +/- a3 ... are all combinations of the above four
                         FROM THIS POINT ON IT WILL BE UNDERSTOOD
THAT COMBINATIONS OF ALL PREVIOUSLY REQUIRED OPERATIONS ARE POSSIBLE
(WITHIN REASON). genprec numbers which are arguments of functions
may appear as such combinations of other genprec functions.
                        
a*b  where a or b is a realmp number.  The other can be
     a real integer, or a realmp number.
a*b  where a or b is a complexmp number.  The other can be
     an integer, a realmp number, or a complexmp number.
     Or a could be cinttomp(1,2)*b to multiply b by (1+2i) for
     example or cfloattomp(1.5E00,2.5E00)*b to multiply b by
     (1.5+2.5i) for example, which is of course the same thing
     as cinttomp(3,5)*b/2 (see below).

a/b  where a or b is a realmp number.  The other can be a
     real integer, or a realmp number.
     BUT if c is a realmp number, c=3/2 is WRONG and will result
     in c=1 (to many significant figures).

a/b where a or b is a complexmp number.  The other can be a
     real integer, a realmp number, or a complexmp number.
     Again, when b is a complexmp number, several things like
     c=cintmp(1,2)/b and c=cfloattomp(1.5E00,2.5E00)/b are correct.

a^b  a and b may both be realmp numbers
     or a may be an integer and b a realmp number
     or a may be a realmp number and b an integer.
     (no floats allowed).

No list of the possibilities compares to what one learns by
looking at the examples and trying whatever comes to mind
onesself.

Comparing realmp quantities (if statements):

For realmp a and b, compare(a,b) returns one of the character
strings "left largest", "equal", or "right largest".  If one has
written
                 which=compare(a,b)
                 if (which=="left largest")   //for example
                   {whatever one would write
                    following if (a>b)}
One must declare char *which. 

Some notes on complexmp quantities:

a=crectopol(b); converts b in rectangular coordinates to a in polar   
a=cpoltorec(b); converts b in polar coordinates to a in rectangular

If you want sin of b in polar coordinates, write
             c=sin(cpoltorec(b));
c is in rectangular coordinates, but if you want it in polar
(for what reason I can't imagine), write
             c=cpoltorec(sin(cpoltorec(b)));

a=compconj(b); //is the complex conjuate of b (a and b both complexmp) 
a=abs(b); //is the absolute value of b (a realmp and b complexmp)
a=realpartof(b);  //is the real part of b (a realmp and b complexmp)    
a=imaginarypartof(b);//is the imaginary part of b (a realmp and b complexmp)
a=cexpitheta(b); //is exp(i*b) (a complexmp and b realmp) 

LIST OF THE ELEMENTARY TRANSCENDENTAL FUNCTIONS:

real: sqrt(a), sin(a), cos(a), tan(a),arcsin(a),arctan(a),sinh(a), cosh(a),
      exp(a),log(a), log10(a)  (note: sinh and cosh are in cgenprec.h)
complex: sqrt(a), sin(a), cos(a), tan(a),arctan(a),exp(a),log(a),
         expitheta(x) where x=theta is real.

a can be a realmp or complexmp number,possibly constructed using
+,-,*,/, and ^ in various combinations as above or constructed from
other transcendental functions (functions of functions) as in sin(cos(a)).
(Note: sin(cos(1)) is checked in example.cc.)  The possibilities are
endless but one must not get carried away.

There exist identities which make it possible to calculate other
functions; namely

     sinh(cz) = sin(i*cz)/i
     cosh(cz) = cos(i*cz)
     arctanh(cz) = arctan(i*cz)/i
     arcsinh(cz) = arctan(i*cz/csqrt(1+cz^2))/i
     arccosh(cz) = arctan(sqrt(1+cz^2)/(i*cz))
     where cz is any complexmp number and i=sqrt(-1).

but these are not coded into genprec.

ADVANCED FEATURES OF GENPREC:  There are features contained in
                               genprec which reflect the author's
long time interest in Pade Approximants.

First, there are provisions for manipulating power series.

For series whose coefficients are real:

s<output of any of the following routines:          //overloaded <
smult(int,s1,s2);                       //s1*s2
stonth(int,s1,p);                         //s^p
sinvert(int,s1);                       //invert s
ssubstitute(int,s1,s2);               //s1(s2)
sadd(int,s1,s2);                        //s1+s2
ssub(int,s1,s2);                        //s1-s2
sder(int,s1);                          //ds(x)/dx
slogder(int,s1);                       //dlogs(x)/dx
smultfac(int,s1,fac);                    //s*fac
seval(int,s,x);                           //s(x)

The above series have to be declared as realmp s[zmaxsizepad];
p is a realmp.  The int is the length (n) of the series:
s=s0+s1*x+s2*x^2+...+sn*x^n. fac is a realmp factor.
x is the realmp point at which it is desired to evaluate the
series.

These make it possible to construct the series for
            (1+2x)^(1/2) * (1+x)^(-1/2)
for example.  (Note that there is no division for series:
so one cannot write s3=s1/s2; rather one write s4=s1*(s2^(-1)), that is
            p=-1;
            s4=stonth(n,s2,p);
            s3=smult(n,s1,s4);
where p is declared as realmp, and the si as realmp si[zprecpad].
The examples illustrate these things.

In the case of series, statements like (functions of functions)
            s3=smult(n,s1,stonth(n,s2,p);  //No.
are forbidden.

For series whose coefficients are complex:

s<output of any of the following:
csmult(int,s1,s2);
cstonth(int,s1,p);
csder(int,s1);
cseval(int,s1,z); 
csadd(int,s1,s2); 
cssub(int,s1,s2);
csmultfac(int,s1,fac);
cslogder(int,s1);

The above have to be declared as complexmp s[cmaxsizepad]. p is a
complexmp.  The int is as above.  fac is a complexmp factor.
z is a complex point at which one wants to evaluate the series.

It is possible to mix up the real and complex types of series:
                scomp=scontoc(int,s1);
converts the realseries declared as realmp s1[zmaxsizepad] to a
complex series scomp declared as complexmp scomp[cmaxsizepad]
(whose imaginary parts are zero, of course).  In this case, one
should set in the beginning zmaxsize and cmaxsize to be the same number.
Such a trick makes is possible to evaluate a real series at a complex
point, for example.

Next, there are provisions for calculating the Pade approximants to
such series, for series whose coefficients are real and series
whose coefficients are complex. (This last is hardly mentioned in
the literature).

the real case:
      //int1/int2 Pade Approximant to s which must be of length int1+int2:
file1<padeapprox(int1,int2,s);              //s is the series
file2<extractnum(int1,file1)                //extract num poly
file3<extractden(int2,file1)                //extract den poly

The declarations must be:
  realmp s[zmaxsizepad];
  pademp file1;
  realmp file2[zmaxsizepad];  //and same for file3

the complex case:

file1<cpadeapprox(int1,int2,s)
file2<cextractnum(int1,file1);
file3<cextractden(int2,file1);

with declaratons:
   complexmp s[cmaxsizepad];
   cpademp file1;
   complexmp file2[cmaxsizepad];  //and same for file3


And finally, there are provisions for finding the roots of the
polynomials which are the numerator and denominator of a Pade
approximant (which is to say, the roots of any polynomial whatsoever,
The terms in the polynomial may be either all real or all
complex (if one is complex they may as well all be complex).
Needless to say, the problem of finding the roots of a polynomial
with complex coefficients is hardly mentioned in the literature.
The method used for solving these polynomials was made up from
scratch by the author and should be replaced by other polynomial
solvers in the future.  The complex polynomial solver is incomplete
(it will not solve complex polynomials in the case that one or
more of the roots is multiple).

realcase:

file1<solvpoly(int,poly);
file2<constructpoly(int,file1);
file3<multpolys(int1,poly1,int2,poly2);

note:  is is possible to make a real polynomial complex by
       using
             polycomp=scontoc(int1,poly);
       where poly is declared as realmp poly[zmaxsizepad] and
       polycomp is declared as complexmp polycomp[cmaxsizepad],
       with zmaxsize and cmaxsize set equal to the same number
       at the beginning of the code.

Above, file1 is the file in which the roots are to be placed;
file2 is the file in which the coefficients of the poly constructed
by multiplying out (x-r1)*(x-r2)*...*(x-rn) is to be placed; and
file3 is the file in which the coefficients of the poly
constructed by multiplying poly1 and poly2 is to be placed.
Its length will be int1+int2, so that zmaxsizepad must exceed that.

The declarations have to be as follows:
          complexmp file1[cmaxsizepad];
because the roots of a real polynomial are complex in general.
One sees that zmaxsize and cmaxsize should be set equal in the
beginning.  Continuing the declarations:
          realmp file2[zmaxsizepad]
and similarly for file3,poly,poly1,poly2) with zmaxsize declared in
the beginning to be big enough to accomodate the largest array which
the problem will lead to.

complexcase:

file1<csolvpoly(int,poly);
file2<cconstructpoly(int,file1)
file3<cmultpolys(int1,poly1,int2,poly2);

In this case the declarations are complexmp file1[cmaxsizepad], etc.

COMPILING THE EXAMPLES

        gxx example.cc -o example.exe -w  (DOS, the Delorie port of
                                           gnu's C++ compiler to DOS)
        g++ example.cc -o example.exe -w  (Linux)

In the case of Linux, one must remove the line
              #include "malloc.c"
at the very top of the file genprecd.h.  "malloc.c" refers to
the memory management in the Delorie port of gnu to DOS.

The -w omits warning messages which are numerous for genprec because
of the use of assembly language.  (In assembly, the origin of an array
need not have a cast as it does in C++.)

There is a batch file (compilex.bat) which compiles all of the examples
one after the other.  About 7 mb of disk space is required for the
18 executables.  Of course they can be deleted when the user wishes.
This batch file is especially useful to check some change in
genprec (usually an addition, but perhaps the name of some function
is annoying).  If all of the examples compile and run correctly the
change has passed inspection.

To repeat what has already been said, genprec will work only with
the intel 486 architecture and the Linux g++ and/or the Delorie port of
gnu's C++ compiler to DOS (available free at www.delorie.com).
Use genpnoas.sem with other compilers and chips.

THE EXAMPLES (in no particular order):
   arithmet.cc  //tests arithmetic mixing multi-precision numbers,
                //float numbers, and signed and unsigned integers
   genpdex2.cc  //some examples of arithmetic and transcendental functions
   cgenpdex.cc  //same, complex case
   cgnlndex.cc  //solution of a complex linear system
   seresdx5.cc  //some manipulations on real series
   cpolydex.cc  //solution of a complex polynomial
   cpadedx1.cc  //pade approximant to complex series, poles and residues
   seresdx2.cc  //the famous example of sqrt((1+2x)/(1+x))
   pid.cc       //pi to 10000 figures--how fast is your computer?
   seresdx3.cc  //substitution of one series into another and inversion
   gnlindex.cc  //solves 50 real linear eqns for 50 unknowns to 128
                //significant figures--14 sec on my 200 mhz pentium pro.
   cseresex.cc  //some manipulations on complex series
   padedex.cc   //trivial pade approximant to a real series
   polydex2.cc  //trivial example of multiplication of two series
   seresdx4.cc  //addition and subtraction of series
   example.cc   //some examples of arithmetic and transcendental functions
   cpadedex.cc  //study of sqrt((1+(2+i)z)/(1+(1+i)z))
   polydex.cc   //solves a number of real polynomials including Wilkinsons
   gnlindex.cpp //compares a genprec code to a basic code (not included
                //in compilex.bat).

In the case of cpadedex.cc, the results raise the question whether there
may exist a generalization of the theory of series of Stieltjes. 

