Blitz Course

IEEE Double precision in Blitz2


I was writing a program about some astronomical calculations (maybe I'll publish it one of the following months) when I realized that the mathematical accuracy of the Blitz2 language was terribly low: the float type can contain only small numbers and the conversion routines (e.g., Val) have some bugs. So I decided to implement the powerful Ieee double precision algorithms in the Blitz2 environment. My work has been inspired by the "longreal" module written in AmigaE by EA van Breemen.

To use my code you just have to XINCLUDE it at the beginning of your program, and make sure you have the "mathieeedoubbas.library" and the "mathieeedoubtrans.library" on your system disk.

The name of the double precision type is "longreal": the longreal type is made of two longwords. You can use it only by means of pointers: that is to say, to create a longreal variable you have to DEFTYPE it as a pointer to longreal and then you have to initialize it using the dNew{} function. Here is an example:

      DEFTYPE.longreal *foo
      *foo=dNew{}

and then you can use *foo with the double precision routines (never forget the star (*)!). If you forget to initialize a variable before using it your machine will GURU. Of course you can handle a longreal variable only by means of the double precision routines because the longreal type isn't a built in type of Blitz2 (it's a sort of trick). Before exiting the program you must free all the longreal variables you have previously initialized: to do this just write

      dFree{*foo}
If you forget to free a variable, the memory allocated for it will be lost.

Next I'll describe the conversion routines. To input a double precision number you write it in a string and then convert it to a longreal using the a2d{} function:

      a2d{string$, *longreal}
The *longreal variable will contain your number. The a2d{} function accepts also the scientific notation: 12e3 or 12E3. To convert it back to a string there are two functions: dFormat{} and dLFormat{}. The former is used for small nonnegative numbers, while the latter acceps any type of number (and outputs also in scientific notation). The sintax is:
      string$=dFormat{*longreal, digits}

      string$=dLFormat{*longreal, digits, max_power}
where: *longreal is the number to convert; digits is the number of ascii characters used to represent the converted number; max_power is a sort of threshold: if the number is greater than 10^max_power then the routine will use the scientific notation.

The other routines constitute all the operations you can do on a double type: in general, they accepts one or two longreals as arguments and put the result of the operation in the first argument, so remember to copy it if you don't want to lose it. To copy a double you use the

      dCopy{*longreal1, *longreal2}

where, as the general rule says, the destination variable is the first one. Unusual routines, as far as their sintax is concerned, are

      long=dFix{*longreal}

converts a double to an integer;

      dFloat{long, *longreal}

converts an integer to a double;

      result=dTst{*longreal}

compares *longreal with the value 0.0: it returns -1 if *longreal<0, 0 if *longreal=0, 1 if *longreal>0;

      result=dCompare{*longreal1, *longreal2}

compares the two longreals and returns: -1 if *longreal1<*longreal2, 0 if *longreal1=*longreal2 and 1 if *longreal1>*longreal2;

      dDouble{IeeeSingle, *longreal}

converts a Ieee single precision value to a double precision value;

      IeeeSingle=dSingle{*longreal}

converts a double precision value to a single precision number;

      dPi{*longreal}

puts the value of Pi (3.141592...) in *longreal. Examples of standard operations are

      dAdd{*longreal1, *longreal2}

adds the two numbers ond returns the result in *longreal1;

      dRad{*longreal}

converts degrees to radians to use in the angular functions;

      dSqrt{*longreal}

computes the square root of *longreal and puts it in *longreal. By the way: there's no checking on errors like passing a negative argument to dSqrt{}, you must do it by yourself; and if you pass a negative value to dSqrt{} your machine will crash without even warning you.

I'm not going to write down all the numerical functions implemented: the source is fully commented so I invite you to have a look at it.

To be sincere I must say that if you convert, for example, the number "1.23" (with a2d{"1.23",*longreal}) and then convert it back to string (with s$=dFormat{*longreal,10}) you will get "1.229999999": well, probably the convertion routines may be improved, but up to now I don't know if this is completely my fault; probably this is due also to the roundoff errors of the Ieee format or to the IeeeDPFloor (and/or IeeeDPCeil) function included in the Ieee libraries that I use during the convertion.

For the source (LHA File), press here.


Main Page


    Written By: Andrea Galimberti  e-mail: fsoft@intercom.it
                Via E.Villoresi
                Turbigo (MI)
                ITALY               tel:    (ITA) - (0)331 - 871009