views:

67

answers:

3

Hi

I am trying to dump the floating point values from my program to a bin file. Since I can't use any stdlib function, I am thinking of writting it char by char to a big char array which I am dumping in my test application to a file.

It's like

float a=3132.000001;

I will be dumping this to a char array in 4 bytes.

Code example would be:-

if((a < 1.0) && (a > 1.0) || (a > -1.0 && a < 0.0))
    a = a*1000000 // 6 bit fraction part.

Can you please help me writting this in a better way.

+2  A: 

Assuming you plan to read it back into the same program on the same architecture (no endianness issues), just write the number out directly:

fwrite(&a, sizeof(a), 1, f);

or copy it with memcpy to your intermediate buffer:

memcpy(bufp, &a, sizeof(a));
bufp += sizeof(a);

If you have to deal with endianness issues, you could be sneaky. Cast the float to a long, and use htonl:

assert(sizeof(float) == sizeof(long)); // Just to be sure
long n = htonl(*(long*)&a);
memcpy(bufp, &n, sizeof(n));
bufp += sizeof(n);

Reading it back in:

assert(sizeof(float) == sizeof(long)); // Just to be sure
long n;
memcpy(&n, bufp, sizeof(n));
n = ntohl(n);
a = *(float*)n;
bufp += sizeof(n);
Marcelo Cantos
Marcelo, could you expand your answer to address endianness issues? Thanks in advance.
Xavier Ho
+1  A: 

Use frexp.

int32_t exponent, mantissa;
mantissa = frexp( a, &exponent ) / FLT_EPSILON;

The sign is captured in the mantissa. This should handle denormals correctly, but not infinity or NaN.

Writing exponent and mantissa will necessarily take more than 4 bytes, since the implicit mantissa bit was made explicit. If you want to write the float as raw data, the question is not about floats at all but rather handling raw data and endianness.

On the other end, use ldexp.

If you could use the standard library, printf has a format specifier just for this: %a. But maybe you consider frexp to be standard library too. Not clear.

Potatoswatter
A: 

If you aren't worried about platform differences between the reader and the writer:

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

...

union float_bytes {
    float val;
    uint8_t a[sizeof(float)]; // This type can be unsigned char if you don't have stdint.h
};

size_t float_write(FILE * outf, float f) {
   union float_bytes fb = { .val = f };
   return fwrite(fb.a, sizeof(float), outf);
}

There are shorter ways to turn a float into a byte array, but they involve more typecasting and are more difficult to read. Other methods of doing this probably do not make faster or smaller compiled code (though the union would make the debug code bigger).

If you are trying to store floats in a platform independent way then the easiest way to do it is to store it as a string (with lots of digits after the . ) . More difficult is to choose a floating point bit layout to use and convert all of your floats to/from that format as you read/write them. Probably just choose IEEE floating point at a certain width and a certain endian and stick with that.

nategoose