Skip to main content
GameDev.net gamedev.net
🔒 Locked

Serialize - data packing

Started by Eitsch Apr 1, 2006 at 2:26 PM 27 replies 2.8k views
Original Post
Eitsch
Eitsch
let's say i have 2 floats. i want to pack them into one big unit (not an array or vector).
Kambiz
Kambiz
struct float2
{
float f1,f2;
};

Where is the problem??
dbzprogrammer
dbzprogrammer
Perhaps you're looking for a double? Set the high 4 bytes to the first float and the next 4 low bytes to the second?
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
Eitsch
Eitsch
dbzprogrammer how to do this?
Kambiz
Kambiz
c/c++ :
union U{	struct {		float f1,f2;	};	double d;};...U u;u.f1 = your_float1;u.f2 = your_float2;your_double = u.d;
dbzprogrammer
dbzprogrammer
I understood the concept, and after a quick pull, I double checked my mental code.

Link.

Fundamentals, bits are what makes a byte. The higher the bit in the sequence, the greater the number it represents. Each bit represents a 2^x number. Normally, we would copy byte for byte, using the & (bit-wise AND) with 255 to determine which bits we want. However, we're doing 4 bytes at a time, so we will have to use the number 4294967295. This sets 32 bits to '1's.

So, follow the code carfully:

double PackFloats(float f1, float f2){  return ((double)f1 << 32) + ((double)f2);}


EDIT: Hit the button too soon. The << is an operator that "shifts" bits. Basically, you're telling the computer that you want to fill in 4 bytes of the double with f1, starting at bit 32, and ends up at bit 63, the last bit (remember, we have bit 0 that makes it a total of 64 bits).
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
Cocalus
Cocalus
Um, packing two small units into a meaningful larger unit only works with unsigned integers. The last bit of code gives you a structure of either two floats or a double.

u.f1 = your_float1;
u.f2 = your_float2;
your_double = u.d;

Is basically filling your_double with meaningless bits.

The
struct float2{
float f1,f2;
}
is most likely what the OP is looking for.
dbzprogrammer
dbzprogrammer
Quote:
Original post by Cocalus
Um, packing two small units into a meaningful larger unit only works with unsigned integers. The last bit of code gives you a structure of either two floats or a double.

u.f1 = your_float1;
u.f2 = your_float2;
your_double = u.d;

Is basically filling your_double with meaningless bits.

The
struct float2{
float f1,f2;
}
is most likely what the OP is looking for.


He has a good point, as floating point precision would get messed up...

But he's just trying to back it up so he could extract it later, would that affect it?
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
dbzprogrammer
dbzprogrammer
Let me add to my previous post here.

How would you de-searilize it?

With a function like the one before, except those numbers that I showed you would actually come into play. Observe:

struct MyStruct{  float f1;  float f2;}MyStruct ExtractDouble(double tempD){  MyStruct returnS;  returnS.f2 = tempD & 4294967295;  returnS.f1 = (tempD >> 32) & 4294967295;  return returnS;}
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
Kambiz
Kambiz
Quote:
Original post by dbzprogrammer
double PackFloats(float f1, float f2)
{
return ((double)f1 << 32) + ((double)f2);
}

This works with interegs but not with doubles:
error C2296: '<<' : illegal, left operand has type 'double'
Cocalus
Cocalus
If he's just packing it to extract it latter then the 2 float structure is what he wants. Using a double is just confusing

This has nothing to do with precision the data structure of a float. They just don't pack like that (the double is as usefull as a random bunch of bits).

A float is
1 sign bit 8 Exponent bits 23 Precision Bits
A double is
1 sign bit 11 Exponent bits 53 Precision Bits

So 2 floats packed into a double like that is
1 sign 8 exponent 23 Precision 1 sign 8 exponent 23 Precision
Where only the first one sign bit lines up with the double.

You can pull the floats back out. But why use a double at all when the structure works just as well and is descriptive of what you're doing.

(Note I'm assuming the compiler packs structures on 4 byte alignments)
Kambiz
Kambiz
Quote:
Original post by Cocalus
Is basically filling your_double with meaningless bits.

But it works...
#include <iostream>using namespace std;union U{	struct {		float f1,f2;	};	double d;};int main(){	//Serialize	U u;	u.f1 = 2.8;	u.f2 = 3.1;	double d = u.d;	//Deerialize	U u2;	u2.d = d;	float f1 = u2.f1;	float f2 = u2.f2;	cout << f1 << endl << f2 << endl;}/*Output:2.83.1*/


OK...
I would use just a struct as I said in my first post.
Or the std::pair class.
Genjix
Genjix
There are possibilities... Like sending out using a network lib that accepts doubles :P Some sort of constraint.
Cocalus
Cocalus
My point is that involving the double is unneeded and confusing.

U u;
u.f1 = 2.8;
u.f2 = 3.1;

float f1 = u.f1;
float f2 = u.f2;

works just as well and is easier to understand.
Kambiz
Kambiz
It is confusing and is it not needed he can use unsigned __int64 too(better than the double)... but he asked how to do it and I just answered.
RDragon1
RDragon1
If you want to serialize it to something like a vector buffer, you could write a bunch of serialization/unserialization functions:

(alternatively, and probably more cleanly, you could make these Get/Put functions member functions of some class, and manage the vector or some other buffer behind closed doors.)

void PutFloat( std::vector<char>& vec, float data ){   vec.insert( vec.end(), reinterpret_cast<char const*>( &data ), reinterpret_cast<char const*>( &data + 1 ) );}float GetFloat( std::vector<char> const& vec, std::size_t index ){   if( index < index + sizeof(float) && index + sizeof(float) <= vec.size() )   {      float val = *reinterpret_cast<float const*>( &vec[index] );      return val;   }   //access would overflow vector boundaries - throw something?   return 0.0f;}


[Edited by - RDragon1 on April 1, 2006 4:40:10 PM]
Cocalus
Cocalus
Quote:
Original post by Kambiz
It is confusing and is it not needed he can use unsigned __int64 too(better than the double)... but he asked how to do it and I just answered.


I was just trying to get across that there are very few good reasons for ever doing it like that.
Kambiz
Kambiz
Quote:

Original post by Eitsch
...not an array or vector...


Quote:

Original post by RDragon1
If you want to serialize it to something like a vector buffer,...
RDragon1
RDragon1
Quote:
Original post by Kambiz
Quote: Original post by Eitsch
...not an array or vector...

Quote: Original post by RDragon1
If you want to serialize it to something like a vector buffer,...


Oops, good call. I saw someone mentioning network serialization, so I threw that up...

That just raises the question - why not a vector?
owl
owl
Quote:
Original post by RDragon1
That just raises the question - why not a vector?


Unrelated to your question, but also a valid one: Why not endianness?

OP, you might want to check the enginuity articles for some developed ideas on serialization that might inspire you.
[size="2"]I like the Walrus best.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.