Bit-twiddling with floats

D

Derek

I have an application that creates lots of small objects that
represent a 2D axis-parallel plane. In short, I these little
objects look like this:

struct Plane {
float location;
enum { X, Y, Z } direction;
};

On my 32-bit platform this structure is 8 bytes, 4 of which
are used to store the direction, a 2-bit value. Memory is
very critical in my world and I'd like to reduce this struct
in size.

An interesting characteristic of my problem domain is that the
float in the Plane structure doesn't have to be exact. I can
sacrifice two LSB bits in the float's fractional part to store
the direction (X, Y, Z) -- and in the process reduce the struct
to 4 bytes, a big saving for my application.

Clearly this code will not be portable, so I'm looking for some
suggestions for alternative solutions or ways to make it less
kludgy:

class Plane {

public:
typedef enum { X, Y, Z } Direction;

Plane(float location, Direction direction) {
// Order matters -- set direction second
m_impl.location = location;
m_impl.direction.value = direction;
}

float getLocation() const {
return m_impl.location;
}

Direction getDirection() const {
return static_cast<Direction>(m_impl.direction.value);
}

private:
union Impl {
float location;
// Depends on the platform's IEEE float layout
struct Bits {
unsigned value : 2;
} direction;
} m_impl;
};
 
R

Rolf Magnus

Derek said:
I have an application that creates lots of small objects that
represent a 2D axis-parallel plane. In short, I these little
objects look like this:

struct Plane {
float location;
enum { X, Y, Z } direction;
};

On my 32-bit platform this structure is 8 bytes, 4 of which
are used to store the direction, a 2-bit value.

I would expect that enum to be only one byte big and the rest to be padding.
The problem is that a float might need to be aligned to a 4 byte boundary
on your system. On some platforms, unaligned accesses are possible, but
slow. Now consider what happens if you have an array of your struct. For
the second element's float to be correctly aligned, the size of the struct
must be a multiple of 4.
Memory is very critical in my world and I'd like to reduce this struct
in size.

An interesting characteristic of my problem domain is that the
float in the Plane structure doesn't have to be exact. I can
sacrifice two LSB bits in the float's fractional part to store
the direction (X, Y, Z) -- and in the process reduce the struct
to 4 bytes, a big saving for my application.

Clearly this code will not be portable, so I'm looking for some
suggestions for alternative solutions or ways to make it less
kludgy:

class Plane {

public:
typedef enum { X, Y, Z } Direction;

Plane(float location, Direction direction) {
// Order matters -- set direction second
m_impl.location = location;
m_impl.direction.value = direction;
}

float getLocation() const {
return m_impl.location;
}

Direction getDirection() const {
return static_cast<Direction>(m_impl.direction.value);
}

private:
union Impl {
float location;
// Depends on the platform's IEEE float layout
struct Bits {
unsigned value : 2;
} direction;
} m_impl;
};

If you don't care much about portability and your system supports unaligned
accesses to float values, there might be a way to make your compiler pack
the structure, so that it takes 5 bytes.
But maybe instead of fiddling around on byte level, maybe you can do a
change on a higher level. I don't know much about your problem, but maybe
instead of storing all the planes including thei direction in one big
container, you could simply use three containers - one for each direction -
and then just store the float values in it.
 
D

Derek

Rolf said:
I would expect that enum to be only one byte big and the rest
to be padding. The problem is that a float might need to be
aligned to a 4 byte boundary on your system. On some platforms,
unaligned accesses are possible, but slow. Now consider what
happens if you have an array of your struct. For the second
element's float to be correctly aligned, the size of the struct
must be a multiple of 4.

That's what I figured. I suppose most compilers have #pragma
directives or other non-portable ways to pack structures, so I
could use that to reduce the struct to 5 bytes. However that's
not portable either, so as long as I'm writing platform-dependent
code, I might as well use my approach and get down to 4 bytes.
If you don't care much about portability and your system
supports unaligned accesses to float values, there might be a
way to make your compiler pack the structure, so that it takes
5 bytes.

That's what I figured. I'll look into it some more.
But maybe instead of fiddling around on byte level, maybe you
can do a change on a higher level. I don't know much about
your problem, but maybe instead of storing all the planes
including thei direction in one big container, you could simply
use three containers - one for each direction -
and then just store the float values in it.

Unfortunately not possible, but thanks for the suggestion. It's
always better to think about optimizations at the highest level
possible first, but I'm certain I can't factor anything out of
this structure.

Thanks.
 
K

Keith H Duggar

struct Plane {
float location;
enum { X, Y, Z } direction;
};

On my 32-bit platform this structure is 8 bytes, 4 of which
are used to store the direction, a 2-bit value. Memory is
very critical in my world and I'd like to reduce this struct
in size.

Have you considered creating a different type for each
direction? As in

struct dim_x {
float location ;
...
} ;

struct dim_y {
float location ;
...
} ;

struct dim_z {
float location ;
...
} ;

and then writing code such as

void draw (
dim_x x ,
dim_y y ,
dim_z z ) ...

This way your coordinates will be 4 bytes only, they will
be type safe, and you can avoid portability problems. This
solution has a number of benefits with respect to reducing
common coordinate related bugs like sending two x
coordinates rather than an x and y etc.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top