| Table of contents of this page | |
|
|
C++ classes for extended precision
This example wraps a set of C++ classes called qd for double double and quadruple double precision calculations. For details of this code please see the work of Yozo Hida. This code is based on qd-2.1.56.
Features used
There are a number of features used here which have not appeared in the other examples. These are all used in the interface for qd
- wrapping of pointers by SWIG
Some of the functions to be wrapped have as an argument a pointer to
uint. This is wrapped by SWIG as
SWIGTYPE_p_uint which it regards as an object to be passed through. In the wrapping this generates a class of the same name which is defined in a file called
classSWIGTYPE_p_uint.d.
- pragma for module level statements
Functions in the interface file which are not contained in a class will be wrapped as D functions defined in the module file. This file needs to have
import statements for the classes used by the functions, and these are inserted using a
pragma command e.g.
| %pragma(dmd) moduleimports="import classqd_real;
import classSWIGTYPE_p_uint;
" |
|
|
- extend command to add functionality to the class in the target language
The SWIG
extend command allows member functions to be defined in the target class in the D language which are not in the C++ class. This is used here for overloaded operators and also to define an output function.
- overloaded operators to allow use of operators in the target language
Examples are given of overloading of arithmetic operators to permit these operators to be used in D.
Code to be wrapped
The code to be wrapped is contained in a series of header files and a library. It must be installed before SWIG can be used. I have used only the version for Linux.
Interface file
| // qd.i SWIG interface for qd package
// developed for the version qd-2.1.56 by Yozo Hida
// from http://www.cs.berkeley.edu/~yozo/
%module qdmath
%{
#define X86
#include <qd/qd.h>
#include <qd/fpu.h>
#include <stdio.h>
#include <sstream>
using namespace std;
%}
%pragma(dmd) moduleimports="import classqd_real;
import classSWIGTYPE_p_uint;
"
%rename(qd_sqrt) sqrt;
qd_real sqrt(const qd_real &a);
%rename(dd_sqrt) sqrt;
dd_real sqrt(const dd_real &a);
%rename (qd_fpu_fix_start) fpu_fix_start;
void fpu_fix_start(uint *old_cw);
%rename (qd_fpu_fix_end) fpu_fix_end;
void fpu_fix_end(uint *old_cw);
%pragma(dmd) classimports="import classdd_real;"
class qd_real {
public:
qd_real();
qd_real(const char *s);
qd_real(const qd_real &dd);
qd_real(const dd_real &dd);
qd_real(double d);
qd_real(int i);
%rename(value) operator double;
operator double();
%rename(dd_value) operator dd_real;
operator dd_real();
%extend {
%rename(opAdd) operator+;
qd_real operator +(const qd_real &c)
{
return *self + c;
}
%rename(opSub) operator-;
qd_real operator -(const qd_real &c)
{
return *self - c;
}
%rename(opMul) operator*;
qd_real operator *(const qd_real &c)
{
return *self * c;
}
%rename(opDiv) operator/;
qd_real operator /(const qd_real &c)
{
return *self / c;
}
char* str() {
/* Note that as from gcc 3.2 this needs the <sstream> header. */
/* Note also the cast on the return needed to fool gcc 3.2 */
std::ostringstream out;
out << *self;
return (char *) out.str().c_str();
}
};
};
%pragma(dmd) classimports="import classqd_real;"
class dd_real {
public:
dd_real();
dd_real(const char *s);
dd_real(const dd_real &dd);
dd_real(double d);
dd_real(int i);
%rename(value) operator double;
operator double();
%extend {
%rename(opAdd) operator+;
dd_real operator +(const dd_real &c)
{
return *self + c;
}
%rename(opSub) operator-;
dd_real operator -(const dd_real &c)
{
return *self - c;
}
%rename(opMul) operator*;
dd_real operator *(const dd_real &c)
{
return *self * c;
}
%rename(opDiv) operator/;
dd_real operator /(const dd_real &c)
{
return *self / c;
}
char* str() {
/* Note that as from gcc 3.2 this needs the <sstream> header. */
/* Note also the cast on the return needed to fool gcc 3.2 */
std::ostringstream out;
out << *self;
return (char *) out.str().c_str();
}
};
}; |
|
|
Run SWIG
The output is the following files
- qdmath.d
- classdd_real.d
- classqd_real.d
- classSWIGTYPE_p_uint.d
- qdmathPINVOKE.d
- qd_wrap.cxx
Example Application
runqd.d demonstrates the precision by computing the square root of two with different types.
| // Experiments with D reals and doubles.
// Imports conversion stuff from C
import std.string;
import std.intrinsic;
import std.math;
import classSWIGTYPE_p_uint;
import qdmath;
import classqd_real;
//import classdd_real;
int main(char[][] args)
{
printf("Compute the square root of two to different precision\n");
printf("In each case square the result and subtract two\n");
double d = 2.;
double d2 = sqrt(d);
printf("double d = %lf, d2 = sqrt(d) = %lf, d2*d2-d = %le\n",d, d2, d2*d2-d);
real r = 2.;
real r2 = sqrt(r);
printf("real r = %Lf, r2 = sqrt(r) = %Lf, r2*r2-r = %Le\n",r, r2, r2*r2-r);
// fpu fixup needed for qd
SWIGTYPE_p_uint u;
qd_fpu_fix_start(u);
dd_real dd2 = new dd_real(2.);
printf("dd2 = %s\n",dd2.str());
dd_real dds = dd_sqrt(dd2);
printf("dds = qd_sqrt(dd2) =\n%s\n",dds.str());
dd_real ddx = dds*dds - dd2;
printf("ddx = dds*dds - dd2 = \n%s\n",ddx.str());
qd_real qd2 = new qd_real(2.);
printf("qd2 = %s\n",qd2.str());
qd_real qds = qd_sqrt(qd2);
printf("qds = qd_sqrt(qd2) =\n%s\n",qds.str());
qd_real qdx = qds*qds - qd2;
printf("qdx = qds*qds - qd2 = \n%s\n",qdx.str());
printf("A little simple arithmetic\n");
qd_real qd1 = new qd_real(1.);
printf("qd1 = %s\n",qd1.str());
qd_real qd3;
qd3 = qd1 + qd2;
printf("qd3 = qd1 + qd2 = \n%s\n",qd3.str());
qd_fpu_fix_end(u);
printf("End of tests\n");
return 0;
} |
|
|
Linux
| dmd -c runqd.d
dmd -c qdmath.d
dmd -c classdd_real.d
dmd -c classqd_real.d
dmd -c classSWIGTYPE_p_uint.d
g++ -c qd_wrap.cxx
g++ runqd.o -orunqd qdmath.o classdd_real.o classqd_real.o classSWIGTYPE_p_uint.o qd_wrap.o -lqd -lphobos -lpthread -lm |
|
|
Note use of library -lqd.
Windows
I have not done this. There is a windows version of qd.
Output
| Compute the square root of two to different precision
In each case square the result and subtract two
double d = 2.000000, d2 = sqrt(d) = 1.414214, d2*d2-d = 2.734358e-16
real r = 2.000000, r2 = sqrt(r) = 1.414214, r2*r2-r = -1.084202e-19
dd2 = 2.0000000000000000000000000000000E0
dds = qd_sqrt(dd2) =
1.4142135623730950488016887242097E0
ddx = dds*dds - dd2 =
-9.8607613152626475676466070660350E-32
qd2 = 2.000000000000000000000000000000000000000000000000000000000000000E0
qds = qd_sqrt(qd2) =
1.414213562373095048801688724209698078569671875376948073176679738E0
qdx = qds*qds - qd2 =
1.519290839321567799595718763129913144675354533379191194604764799E-64
A little simple arithmetic
qd1 = 1.000000000000000000000000000000000000000000000000000000000000000E0
qd3 = qd1 + qd2 =
3.000000000000000000000000000000000000000000000000000000000000000E0
End of tests |
|
|