FXDR

David W. Pierce
Scripps Instititution of Oceanography

What is it?

FXDR is a library that allows you to make calls to the XDR (eXternal Data Representation) routines from Fortran. You almost certainly already have the XDR routines on your workstation--with FXDR you can easily call them from Fortran. In practical terms, this means that you can read and write unformatted binary files in your Fortran code which are portable between different platforms. Write your binary on a Cray, read it on a DEC, write it on an SGI, read it on a HP--it doesn't matter.

  • Download the source for FXDR version 1.4a. I've tested it on DEC Alphas and PMAX, Crays, SGIs, and HPs.

    Current version 1.4a, released 13 November, 1998.

    (change log).

    More detailed information on FXDR

    Table of Contents

    1. What is FXDR?
    2. Why would I want to use the XDR routines via the FXDR library?
    3. How do I use FXDR?
    4. More detail on using the FXDR library
    5. An important note on precision
    6. Yet another note on precision
    7. Interpreting the results of the test program
    8. More complete information
    9. Copyright

    What is FXDR?

    The FXDR library is a set of Fortran routines which provide an interface to the XDR routines which already exist (almost certainly) on your workstation or mainframe. I.e., it provides an easy and convenient way to use the XDR ability of your computer from Fortran.

    Back to Table of Contents

    Why would I want to use the XDR routines via the FXDR library?

    In a single sentence: if you use the FXDR routines in your Fortran codes to write out your binary data files, then you can move those data files around to any of the different machines you use, and the data will be read in correctly! No more translating between different platforms! No more huge ASCII files to deal with! OK, that was more than a single sentence, but I got enthusiastic.

    The XDR library is what computers use to talk to each other for RPC (Remote ProCedure) calls over the network. When RPC was first designed, the makers realized that different vendor's computers couldn't easily talk to each other over a network because of byte ordering and precision differences. For example, binary data written on a Sun can't be directly read on a DEC because the byte ordering is opposite on the two; and Cray floating point binary data can't easily be read on anything else because Cray uses their own format, not IEEE (as most everyone else uses). So, the RPC designers standardized a particular way of representing data (the eXternal Data Representation, or XDR).

    If you write out data using the XDR libraries, then read it in using the XDR libraries, then it doesn't matter what platform you either wrote it on or read it on. You can write it on the Sun, and read it on the DEC, or write it on a Cray and read it on an SGI. As long as you go through the XDR library, the low level format of the data will be understood correctly. (You still have to know the high level format of the data. Which is to say, if you wrote a single precision floating point number, you must instruct the routines to read in a single precision floating point number and not something different such as a integer or character string.)

    Back to Table of Contents

    How do I use FXDR?

    You just replace your Fortran unformatted binary write statements with calls to the appropriate FXDR library routine.

    Example:

    Replace

            parameter (nx=80,ny=100)
            real    coeffs(nx,ny)
            open(ilun, file='testdata', form='unformatted')
            write(ilun) coeffs
    

    With

            parameter (nx=80,ny=100)
            real    coeffs(nx,ny)
            ixdrs = initxdr('testdata.xdr', 'w')
            call xdrrmat( ixdrs, nx*ny, coeffs )
    

    Pretty easy, eh? To read in that same data:

    Replace

            open(ilun, file='testdata', form='unformatted')
            read(ilun) coeffs
    

    With

            ixdrs = initxdr('testdata.xdr', 'r')
            call xdrrmat( ixdrs, nx*ny, coeffs )
    

    Note that the call to the FXDR routine is exactly the same whether you are reading or writing; whether you actually read or write is determined by whether you called the 'initxdr' routine with a 'r' or 'w' as the second argument. This is an improvement over Fortran, where the call to open the file is exactly the same whether you are reading or writing, but you call different routines ('read' or 'write') to accomplish the one you want.

    Back to Table of Contents

    More detail on using the FXDR library

    To use the FXDR library you first open the XDR-format file using the 'initxdr' routine. This routine returns an integer which is the ID number which all the XDR routines will use to indicate which XDR file you want to work with. The first argument to 'initxdr' is the name of the file, and the second argument is either 'r' or 'w' for reading or writing:

            character*(*) filename
            character*1   mode
            integer       id
            id = initxdr( filename, mode )
    

    Then you replace both your 'read' and 'write' calls with a call to one of the following routines:

    Name      Bits  Fortran type of argument
    --------- ----  --------------------------------------------------------
    xdrdouble 64    double precision floating point number
    xdrdmat   64    array of double precision floating point numbers
    xdrint    32    integer
    xdrimat   32    array of integers
    xdrreal   32    single precision floating point number
    xdrrmat   32    array of single precision floating point numbers
    xdrreal64 64    single precision floating point number
    xdrrmat64 64    array of single precision floating point numbers
    xdrstring n/a   character*(*)
    

    The 'Bits' column shows how many significant bits are saved in the XDR file.

    The scalar (i.e., single value, not array) routines all take exactly two parameters:

  • the xdr file ID, which was the integer returned by the 'initxdr' call.
  • the variable to either read or write.
  • The array routines all take exactly three parameters:

  • the xdr file ID, which was the integer returned by the 'initxdr' call.
  • the TOTAL number of elements in the array.
  • the array to either read or write.
  • Back to Table of Contents

    An important note about precision

    It is IMPORTANT to understand that the precision referred to above (for example, the 'single' precision of routine 'xdrreal' or the 'double' precision of routine 'xdrdouble') is SET BY YOUR COMPILER, not by the FXDR library. This matters, because different compilers have different default precisions (as in, number of bits) associated with the names 'single', 'double', etc. At the time of writing this, this makes the biggest difference when moving XDR files between Crays and workstations such as Suns, HPs, or DECs, because by defalt the Cray Fortran compiler uses a 'single' precision of 64 bits and a 'double' precision of 128 bits, while the Sun, HP, and DEC use a 'single' precision of 32 bits and a 'double' precision of 64 bits. (You might get a similar effect on a workstation if you compile with a flag such as '-r8' which instructs the compiler to make all 'single precision' variables default to 8 bytes [64 bits] of precision).

    The upshot is that if you use a Cray to write a Fortran single precision floating point number into an XDR file using routine 'xdrreal', only 32 bits of the original 64 bits will be written. But, you can't use routine 'xdrdouble' to write all 64 bits correctly, because that routine expects to be passed a Fortran double precision floating point variable, not a single precision variable.

    To get around this, there is a set of special routines which take 'single precision' variables as defined by the Fortran compiler and write them out with 64 bits (these are the 'xdrreal64' and 'xdrrmat64' routines). To read these in on a workstation where a real is only 32 bits, you should use the 'xdrdouble' or 'xdrdmat' routines and supply a *double* precision floating point variable to receive the 64 bits of valid data. (To read these in on a Cray, you just use the same routine which wrote the data out in the first place--'xdrreal64' or 'xdrrmat64').

    To sum up for 64-bit precision:

    Write single precision values on a Cray (or workstation with 64 bit Fortran reals) with 'xdrreal64' or 'xdrrmat64', then read them into double precision values on a regular workstation with a call to 'xdrdouble' or 'xdrdmat'.

    Write double precision values on a workstation with 'xdrdouble' or 'xdrdmat', then read them into single precision values on a Cray (or workstation with 64 bit Fortran reals) with a call to 'xdrreal64' or 'xdrrmat64'.

    Note that you don't have to use 64-bit precision; you can use 32-bit precision if you want (I often do, the files are half as big). This is easy to do; just write out real*4 type numbers on both the Cray and the workstation, and use the 32-bit calls such as xdrrmat and xdrreal.

    Back to Table of Contents

    Yet another important note about precision

    Unfortunately, that's not all you should know about precision. There is also the problem that Crays (at the moment--new Crays might change this) use a completely different scheme for representing numbers internally than do workstations. Crays use "Cray floating point format" (duh) while workstations use "IEEE floating point format". Well, the underlying XDR libraries which FXDR calls always use IEEE floating point format, so if you always work on a workstation then everything is fine and please ignore this paragraph despite the fact that you've already read a lot of it. If you work on Crays, though, you need to be aware that putting data into an XDR file and then immediately reading it back in WILL NOT leave you with exactly the same floating point number which you started with. It will likely be different in the last bit position or so. This is a tiny difference, and to put it into perspective, the Cray compiler will itself do things to your code (and warn you that it is doing them) which can change your results this much, for the sake of making the code run faster. However if you just can't live with losing a bit of precision in your numbers then please erase your copy of this library and for God's sake start drinking decaffinated coffee.

    Back to Table of Contents

    Interpreting the results of the test program

    There is a test program included with the distribution. When you "make test" then the program (called--if you can possibly believe it--"test.F") is compiled and runs, testing the FXDR library. It:

  • Writes out a new .xdr file, called "test.xdr"
  • Reads in that file which it just created ("test.xdr") and checks to see if it has the expected values.
  • Reads in a .xdr file which I generated on a DEC alpha ("test.orig.xdr") to see if it has the expected values.
  • Now what often happens is that there is some precision loss somewhere along the way, usually in the last bit. The first part of the test, which creates a .xdr file and then reads it back in, rarely shows any loss of precision on a machine which itself uses IEEE floating point format (most workstations including DEC, Sun, HP, and SGI). So frequently that part will pass with no warnings of precision loss. On the other hand, if you run it on a Cray (which does NOT use IEEE floating point format) then you will see some loss of precision at this point. For single precision floating point values, 1 part in 10**7 is about the last bit; for double precision floating point values, 1 part in 10**14 is about the last bit. So if you see losses of precision of this amount or smaller (and you almost certainly WILL) then it just means that the last bit is getting munged. You have to decide for yourself whether this is a problem or if you can live with it. Remember, the settings of compiler flags affecting the optimization level frequently alter your results to this level of precision.

    The second part of the test reads in a .xdr file which I generated on a DEC alpha and checks it for the proper values. Unless you happen to be running on a DEC alpha yourself, then you will almost certainly get some warnings of loss of precision at this point.

    Back to Table of Contents

    Complete information

    There is more complete information on how to build, install, and configure the FXDR library in the README file, so be sure to look through that after downloading the source. Also, don't forget to look at the man pages (man fxdr).

    Back to Table of Contents

    Version Information

    1.4 to 1.4a: Nov 13, 1998. Minor modifications to 'unicos' system defines for newer Cray compilers.

    1.3 to 1.4: Nov 14, 1997. Added support for 'short' type. Added more information for users of HP, Linux, and sun systems.

    1.2 to 1.3: July 213, 1996. Added check to 'mode' passed to routine 'initxdr'.

    1.1 to 1.2: March 18, 1996. Fixed bug in makefile. Added "local_filename" to routine "cxdrinit.c" to make it work under UNICOS 9.0.1 on the C90.

    1.0 to 1.1: November 28, 1995. Added routine 'xdrrewind'.

    Back to Table of Contents

    Copyright

    Copyright (c) 1995 The Regents of the University of California. All rights reserved.

    Redistribution and use in source and binary forms are permitted provided that (1) source distrubutions retain this entire copyright notice and comment, and (2) distributions including binaries display the following acknowledgement: ``This product includes software developed by the University of California, San Diego and its contributors'' in the documentation or other materials provided with the distribution and in all advertising materials mentioning features or use of this software. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

    Back to Table of Contents

    Back to David Pierce's home page.

    Last modified March 18, 1996