How to accurately write float value to bin file
I am trying to dump floating point values from my program into a bin file. Since I cannot use any stdlib function, I am going to write a char char to a large char array that I dump in my test application to a file.
Like it
float a=3132.000001;
I'll dump this into a 4 byte char array.
Sample code:
if((a < 1.0) && (a > 1.0) || (a > -1.0 && a < 0.0))
a = a*1000000 // 6 bit fraction part.
Could you please help me write this better.
a source to share
Assuming you plan to read it back into the same program on the same architecture (no content issues), just write the number directly:
fwrite(&a, sizeof(a), 1, f);
or copy it from memcpy to your intermediate buffer:
memcpy(bufp, &a, sizeof(a));
bufp += sizeof(a);
If you have to deal with problems with specialists, you can be mean. Insert float into 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 back:
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);
a source to share
Use frexp
.
int32_t exponent, mantissa;
mantissa = frexp( a, &exponent ) / FLT_EPSILON;
The sign is fixed in the mantissa. This should handle denormals correctly, but not infinity or NaN.
Writing exponent
and mantissa
will definitely take more than 4 bytes, since the implicit bit of the mantissa was made explicit. If you want to write float as raw data, the question is not about floats in general, but rather for handling raw data and content.
On the other end, use ldexp
.
If you can use the standard library printf
has a format specifier only for this: %a
. But perhaps you think that is frexp
also the standard library. Dont clear.
a source to share
If you're not worried about the platform difference between reader and author:
#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 are more typed and harder to read. Other ways to do this probably don't make the compiled code faster or smaller (although concatenation will make the debugging code larger).
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 more digits after.). More complex is choosing a floating point bit layout to use and converting all of your floats to / from this format as you read / write them. Probably just choose IEEE floating point with a specific width and a specific end and stick with that.
a source to share