[comp.lang.c] i/o of floats

charest@ai-ganymede.JPL.NASA.GOV (Len Charest) (08/22/90)

I have a large (~40 MB) file of floating point values stored in binary
under the following format:
	float = 32-bit word
	bit 31 = sign bit for exponent
	bits 30-23 = exponent (8 bits)
	bits 22-0 = mantissa (always positive)
(Apparently this is some IEEE standard.)
The floats are stored in contiguous "records" of length N, where N is
determined at *run-time*. This means that I can minimize the number of
calls to fscanf by reading an entire record of floats from the disk (as
an array of chars) and then parsing the record in C. Example:
	let N = 256			/* N is known a priori for now */
	unsigned char record[N + 1];	/* add one for terminating `\0` */
	fscanf(fp, "%256s", record); 	/* read the record from disk */
Now how do I interpret each 4-byte "word" of record as a floating point number?

I merely need to print each float onto stdout. However, I've been away
from C programming for a while and I'm confused about how to solve this
problem. I am assuming that the fscanf library function does not alter
the bits it reads when the conversion spec indicates a character string.
That is, interpretation of the raw bits stored on file should be
completely under my control. On the other hand, I really would like to
avoid writing a mammoth floating point conversion routine.

Suggestions/solutions are greatly appreciated. Respond to this list or
directly to me at charest@ai-cyclops.jpl.nasa.gov

Thanx,
Len

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (08/22/90)

In article <9232@jpl-devvax.JPL.NASA.GOV>, charest@ai-ganymede.JPL.NASA.GOV (Len Charest) writes:
> I have a large (~40 MB) file of floating point values stored in binary
> [using IEEE-754 single precision (32-bit) format]
> The floats are stored in contiguous "records" of length N, where N is
> determined at *run-time*. This means that I can minimize the number of
> calls to fscanf by reading an entire record of floats from the disk (as
> an array of chars) and then parsing the record in C.

Ick.  You can't use fscanf() with such data *at all*.  fscanf() is for
reading *text*.  To read a record of N bytes as N/4 floats, do

	#define N /*whatever*/
	#define NFLOATS ((N)/sizeof (float))
	float the_record[NFLOATS];
	int floats_read;
	...
	floats_read = fread(the_record, sizeof (float), NFLOATS, the_stream);

Now you have 32-bit floats in memory and can do
	printf("%g", the_record[floats_read-1])
or whatever takes your fancy.

-- 
The taxonomy of Pleistocene equids is in a state of confusion.

tchrist@convex.COM (Tom Christiansen) (08/22/90)

In article <9232@jpl-devvax.JPL.NASA.GOV> charest@AI-Cyclops.JPL.NASA.GOV writes:
>I have a large (~40 MB) file of floating point values stored in binary
>Now how do I interpret each 4-byte "word" of record as a floating point number?
>I merely need to print each float onto stdout. 

If I understand your problem, it's pretty easy to solve.

They're floats on the disk, so read them in that way.  I assume that your
machine is also in IEEE format.  Otherwise you'll have to write an IEEE-
to-native conversion function, probably using bit fields or bit masks.

The simple case (same FP format) is easy.  I use stdio because you
did and it optimizes the I/O buffering pretty well.  

    /*
     * read n floats in binary from stdio pointer fp,
     * printing on stdout one per line.  returns i/o success.
     * CAVEAT EMPTOR: untested
     */
    #define FOK(F) (!(feof(F) || ferror(F)))

    read_floats(fp, n)
	FILE *fp;
	int   n;
    {
	float num;

	ASSERT(fp != NULL);
	ASSERT(n > 0);

	while (FOK(fp) && n-- && fread(&num, sizeof(num), 1, fp)) 
	    printf("%14.8f\n", num);

	return FOK(fp);
    }

--tom
--
 "UNIX was never designed to keep people from doing stupid things, because 
  that policy would also keep them from doing clever things." [Doug Gwyn]