Sign in to follow this  
gchris6810

Why do I get ridiculous floating point values when I read a binary file?

Recommended Posts

Hi,

 

I've developed a custom binary format exporter in Blender for my model's mesh, material and animation data. When I attempt to load the file data Integer values are read correctly in the header but when I go to read the actual per-vertex data the values are often either 0.0 or something like this monstrosity:

 

-6906376617984.000000

 

 

I think the problem might have something to do with the fact the values are floats. I have tried the following code to help solve the problem but it doesn't fix the problem.

float RootFile::readFloat( void )
{
uint8_t b[4];
RootDwordFloat d;

read( b, 4, 1 );
d.dword_value = ((uint32_t)b[3] << 24) |
		((uint32_t)b[2] << 16) |
		((uint32_t)b[1] << 8) |
		((uint32_t)b[0]);
return d.float_value;
}

Do you have any idea how I could solve this? Any replies are appreciated.

Share this post


Link to post
Share on other sites

How was the float written?

 

EDIT:I mean, what does the documentation say the convention for byte order is? And can you post an example of four bytes from a file and what float you think they encode?

Edited by Álvaro

Share this post


Link to post
Share on other sites

I think these are the answers to your questions but I may be wrong:

 

Byte order: I think the byte order is probably little endian but I can't be sure as I just used the blender python 'struct.pack' command and then 'file.write'

 

Sample bytes and float value: Here I will give what I think is what you are looking for with the bytes and their proper float value I took one sample from each mesh in the model:

 

mesh 1: 238 1 104 26  float value: 0.517633 
 
mesh 2: 102 0 158 162  float value: 0.177884 
 
mesh 3: 58 0 99 64  float value: -0.090596
 
mesh 4: 46 0 100 8  float value: -1.447870
 
mesh 5: 132 0 201 212  float value: 1.137005

Share this post


Link to post
Share on other sites

Try using a union

union FloatInt
{
    int i;
    float f;
}

FloatInt fi;
fread(&fi.i,sizeof(FloatInt),1,fp);

Are you sure blender wrote a float and not a double?

Share this post


Link to post
Share on other sites

I did actually try using a union although it may not have been clear in my code example in my first post I use the type RootDwordFloat which is the following union:

 

EDIT: I'm pretty sure it is not a double.

typedef union
{
        uint32_t dword_value;
	float float_value;
} RootDwordFloat;
Edited by gchris6810

Share this post


Link to post
Share on other sites
First things first:

You have a custom binary format exporter, which I presume you've written? If so then it should be a simple matter of reversing your writes. If its not one that you've written but written by someone else, then you should read their documentation on the file format.

Endianness is important, you need to know if the values are stored in big or little endian when written. If you're doing raw writes, then chances are they're in the native endianness which is likely to be little endian.

If you're going to use a union like that, avoid bitshifting entirely, just stick your array of bytes straight in the union:

union RootFloat {
    uint8_t bytes[4];
    float value;
};
}

Share this post


Link to post
Share on other sites

Didn't get why you can't just read the value as a float, something like:

    float f;
    fread (&f, sizeof(float), 1, filePointer);

But, other approaches are printing the file offset (take a look at ftell function) to check if you are actually reading the right point of the file.

 

Print the byte per byte to validade if it is correct. Use this code to print byte per byte:

    float f = 0.517633;
    int i = 0;
    uint8_t* u = &f;
    for (i = 0; i < sizeof(float); ++i){
        printf("%02x ", u[i]);
    }
    printf("\n");

Here (linux 32 bits), it prints:

99 83 04 3f

Edited by KnolanCross

Share this post


Link to post
Share on other sites

Sorry but I am unfortunately still getting the same random values even with your simplified union load procedure. In answer to KnolanCross unfortunately I can't do that either. Naturally that was the first thing I tried.

Edited by gchris6810

Share this post


Link to post
Share on other sites

Do you know how to use an hex editor or hexdump (if you are using linux)?

 

You can print the value you are expection as a binary sequence, look for it in the binary file using the hexeditor and check if you are reading the correct position. The last problem I can think of is endianess, also detectable by using a hex editor to check the binary file you created.

Share this post


Link to post
Share on other sites

mesh 1: 238 1 104 26  float value: 0.517633


I can't think of any way to interpret those 4 bytes as a float anywhere near 0.517633: Any floating-point number between 0.5 and 1.0 should start with a byte with the value 63. Your second bytes are all 0 or 1, which seems suspicious. Perhaps you are looking in the wrong part of the file?

Share this post


Link to post
Share on other sites

Before reading the value print the result of a ftell() function. This will be the offset the code is reading.

Open the file in the hex editor and find what is the values there.

 

You may use an reverse code to print what the float should actually be, for instance:

    uint8_t array[4] = {0x99, 0x83, 0x04, 0x3f}; // here you put the 4 bytes on the offset being read.
    float* fp = array;
    printf("%f\n", *fp);

This will print 0.517633.

 

BTW: Are you checking for errors in you file read, open, write operations? Did you remember to call close in the program that created the binary file?

Share this post


Link to post
Share on other sites

Something like this:

    uint8_t array[sizeof(float)]
    read(array, sizeof(float), 1, filepointer);
    
    uint8_t reverseArray[sizeof(float)];
    for (int i = 0; i < sizeof(float); ++i){
        reverseArray[i] = array[sizeof(float)-i-1];
    }


    float* fp = reverseArray;
    printf("%f\n", *fp);

Edited by KnolanCross

Share this post


Link to post
Share on other sites

Thank you everybody who posted a reply your responses have been very useful. I think i'll tinker with it by myself to try and find the solution.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this