Last update March 7, 2012

Dwith Swig / Examples /
Qdmath



Table of contents of this page
C++ classes for extended precision   
Features used   
Code to be wrapped   
Interface file   
Run SWIG   
Example Application   
Compile and Link   
Output   

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    

swig -dmd -c++ qd.i

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;
}

Compile and Link    

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


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: March 7, 2012 20:27 (diff))