CAPD::DynSys Library  6.0.0
Multiple-precision in CAPD

Requirements

To use multiple-precision you need to install packages

  • libgmp, libgmp-dev
  • libgmpxx
  • libmpfr, libmpfr-dev.

They can be also compiled and installed from sources even under Windows, but in this tutorial we assume for simplicity that you are under Linux.

Multiple-precision data types

The CAPD library uses generic programming (templates) therefore switching from double precision to multiple precision is really simple. You only have to replace the base building blocs (types) of the CAPD classes.

Use capd::MpFloat instead of double. MpFloat is a C++ class which represents multiple-precision floating point number with correct rounding.

To define multiple-precision interval you can write

Definition of template class Interval.
Definition: Interval.h:83
Interval< MpReal, MpReal > MpInterval
Definition: MpInterval.h:26

Then in your code use MpInterval instead of DInterval (interval with double precision endpoints). To define MpInterval include capd/intervals/MpInterval.h instead of DoubleInterval.h or Interval.h.

If you use typedef's in your programs then most probably you need to change only two lines.

Examples

The following examples shows how to define multiple-precision variables, initiate them and use them as base types for other CAPD classes: Interval, Vector and Function.

These examples can be found in the capd/capdDynSys/examples/multiprecExample directory.

To compile first example one can invoke:

g++ -o mpExample1 mpExample1.cpp `CAPD_BUILD_DIR/bin/capd-config --cflags --libs`
Definition: ApplicationDesc.h:23

where CAPD_BUILD_DIR is a root directory of the CAPD library or directory to which the CAPD library was installed.

You can also use provided Makefile and simply call

make mpExample1

Basic usage of multiple precision floating points

// Copyright (C) CAPD group
//
// This file constitutes a part of the CAPD library,
// distributed under the terms of the GNU General Public License.
// Consult http://capd.ii.uj.edu.pl/ for details.
#include <iostream>
#include "capd/capdlib.h"
#include "capd/mpcapdlib.h"
using namespace std;
using namespace capd;
int main(){
MpFloat::setDefaultPrecision(100);
MpFloat::setDefaultRndMode(MpFloat::RoundNearest);
MpFloat a = 1,
b("1.2345678901234567890123456789"), // string allows to input any number of digits
c(1.12112, MpFloat::RoundUp, 10), // use only 10 mantisa bits and round up the initial value 1.2112
d(1.234567890123456789), // only 15 digits is used to initialize (1.234... is converted to double)
e(1.234567890123456789L); // here we say (L suffix) that parameter is of a long double type
cout << "\n Precision used (in mantisa bits): " << capd::multiPrec::MpReal::getDefaultPrecision() <<"\n";
cout.precision(30);
cout << "\n a = " << a << "\n b = " << b << "\n c = " << c
<< "\n d = " << d << "\n e = " << e << endl;
return 0;
}
static PrecisionType getDefaultPrecision()
returns default precision of all operations
Definition: MpReal_Base.hpp:120
int main(int argc, char *argv[])
Definition: argdemo.cpp:81
@ RoundUp
Definition: DoubleRounding.h:28
@ RoundNearest
Definition: DoubleRounding.h:28
Multiple Precision version of CAPD library.
::capd::multiPrec::MpReal MpFloat
Definition: mplib.h:26
Definition: Logger.h:88

First we set precision to 100 mantisa bits (about 30 decimal digits)

MpFloat::setDefaultPrecision(100);

and we set MpFloat to round numbers to the nearest representable.

MpFloat::setDefaultRndMode(MpFloat::RoundNearest);

Now we create several MpFloat objects using different possible constructors

MpFloat a = 1,
b("1.2345678901234567890123456789"), // string allows to input any number of digits
c(1.12112, MpFloat::RoundUp, 10), // use only 10 mantisa bits and round up the initial value 1.2112
d(1.234567890123456789), // only 15 digits is used to initialize (1.234... is converted to double)
e(1.234567890123456789L); // here we say (L suffix) that parameter is of a long double type

and print them on a screen

cout << "\n Precision used (in mantisa bits): " << capd::multiPrec::MpReal::getDefaultPrecision() <<"\n";
cout.precision(30);
cout << "\n a = " << a << "\n b = " << b << "\n c = " << c
<< "\n d = " << d << "\n e = " << e << endl;

Intervals with multiple-precision endpoints

#include <iostream>
#include "capd/capdlib.h"
#include "capd/mpcapdlib.h"
using namespace std;
using namespace capd;
int main(){
MpFloat::setDefaultPrecision(200);
MpFloat a = 1,
b("0.1",MpFloat::RoundDown), // 0.1 is not representable so we round down
// to use it as left endpoint
c(0.5); // 0.5 is representable so no rounding needed
MpInterval ia(a),
ib(b,c),
ic("-1.2345678901234567890","2020.202020202020202002");
cout.precision(60);
cout << "\n ia = " << ia << "\n ib = " << ib << "\n ic = " << ic << endl;
return 0;
}
MpReal represents multiple precision real number with controlled rounding.
Definition: MpReal.h:65
@ RoundDown
Definition: DoubleRounding.h:28
int main()
Definition: mpExample2.cpp:22

Multiple-precision vectors and functions

#include <iostream>
#include "capd/capdlib.h"
#include "capd/mpcapdlib.h"
using namespace std;
using namespace capd;
int main(){
MpFloat::setDefaultPrecision(100);
MpFloat::setDefaultRndMode(MpFloat::RoundUp);
MpFloat a(1),
b("0.1",MpFloat::RoundNearest), // 0.1 is not representable and
// we want round it to nearest representable
c(0.125); // 0.125 is representable so no rounding needed
MpVector v(3);
v[0] = a; v[1] = b; v[2] = c;
char formula[] = "var:a,b,c;fun:a+b+c;";
MpFunction f(formula);
cout.precision(30); // 100 mantisa bits correspond to 30 decimal digits
cout << "\n Function : " << formula
<< "\n argumets : " << v
<< "\n f(a,b,c) = " << f(v) << endl;
return 0;
}
Class Function represents a function .
Definition: Function.h:41
Definition: Vector.h:54
int main()
Definition: mpExample3.cpp:23

Multiple-precision types from the mpcapd library

Instead of including a lot of header files, "building" your own types and defining new names for them (using typedef), you can include just one header file

#include "capd/mpcapdlib.h"

and use types which are included in the mpcapd library. It lets you to start writing your code without repeating every time the same tedious things (i.e. including a lot of files and making many typedefs). It also shorten compilation time, because they are not recompiled when your program is built.

In general names defined in the mpcapd library agree with those defined in examples above, with one difference: they are defined in the capd namespace. Therefore you can simply replace all "includes" and "typedefs" in the above examples by two lines

#include "capd/mpcapdlib.h"
using namespace capd;

and they should compile and work exactly the same.

The naming convention is as follows:

  • MpFloat is the name of the base multiple precision type,
  • if CLASS is the name of the template class then the name of a multiple precision type will be
    • MpCLASS for "nonrigorous" type
      e.g. MpInterval, MpVector, MpMatrix, MpFunction, MpMap, MpOdeSolver etc.
    • MpICLASS for rigorous, interval type
      e.g. MpIVector, MpIMatrix, MpIFunction, MpIMap, MpIOdeSolver etc.

Remark: Not all possible templates are compiled into mpcapd library e.g vectors of a fixed size are not included. Instead we include only those that are often used. The list of types and their names can be found in the mplib.h file in the "include" directory of the corresponding module (e.g. capd/include/intervals/mplib.h).

#include <iostream>
#include "capd/capdlib.h"
#include "capd/mpcapdlib.h"
using namespace std;
using namespace capd;
int main(){
MpFloat::setDefaultPrecision(100);
MpFloat::setDefaultRndMode(MpFloat::RoundUp);
MpFloat a(1),
b("0.1",MpFloat::RoundNearest), // 0.1 is not representable and
// we want round it to nearest representable
c(0.125); // 0.125 is representable so no rounding is needed
MpVector v(3);
v[0] = a; v[1] = b; v[2] = c;
cout << "\n v = " << v;
MpFunction f("var:a,b,c;fun:a+b+c;");
cout << "\n f(a,b,c) = " << f(v) << endl;
return 0;
}
int main()
Definition: mpExample4.cpp:23