Jump to content
  • Advertisement
Sign in to follow this  
Steve-B

How to reverse the bytes in a float???

This topic is 4822 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi Hi everyone I have an odd problem which has left me completely stumped. I am loading in a file format which has the byte ordering in the Big-Endian format. When I read in data from the file I have to reverse the bytes to the win32's Little-Endian format. Now this isn't too much of a problem as I've set up a few methods within my program class which reads in data from the file (be it unsigned long, int, unsigned int) and then copies the data (using shifting) into a 4-byte bit-field structure. Reversing the bytes and updating the variables real value is then the simple matter of a macro which shifts the bytes to their correct positions. This method works perfect for int's unsigned long's etc BUT not for float's. C does not allow shifting within floating point variables and floats can't be stored within a bit-field structure. I tried reading the data into an unsigned long splitting up the byte and then copying the resultant value to a floating point variable but of course the number was completely wrong. I then found out this is because of the IEEE format. Seems a bit like a vicious circle to me?? Is there any way out? I did find a horrible hack solution where I read the float data into an unsigned long, reversed the bytes and then wrote the data back out to a temporary file and then read the data from this file into a floating point variable to retrieve the proper value. This works but of course, it's not exactly ideal. I'm really stuck for a decent solution to this problem. Anyone had any experience of this problem?? Steve

Share this post


Link to post
Share on other sites
Advertisement
Not sure that this'll work, but have you tried casting a pointer to the float, to a pointer to a byte, and making the changes that way?

UChar* bytes = reinterpret_cast<UChar*>( &floatVar );

//Copy the value of the first byte to the second byte
*(bytes) = *(bytes+1);

Share this post


Link to post
Share on other sites
Im not total up on big/little endian so if this is all wrong just ignore it:

maybe you could do something like this?


float fBigE;
float fLittleE;

char* p1 = (char*)&fBigE;
p1+= 3;
char* p2 = (char*)&fLittleE;

for(int i = 0; i < 4; ++i)
{
*p2 = *p1;
--p1;
++p2;
}




Hope that helps. Like I said if its wrong then ignore me:)

Share this post


Link to post
Share on other sites
I would so something like this


union ManipFloats
{
float _f;
char _c[4];
};



_f and _c[4] share the same memory space.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Why do you use a bitfield for conversion. An uint32 can do the job, as this macro shows:


#define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | (((uint32)(A) & 0x00ff0000) >> 8) | (((uint32)(A) & 0x0000ff00) << 8) | (((uint32)(A) & 0x000000ff) << 24))


Then try this, it's quite ugly but should work


uint32 intVal = *((uint32*)(&floatVal));
*((uint32*)(&floatVal)) = htonl( intVal );


Share this post


Link to post
Share on other sites
or you could be cool:


// the xor byte swap
inline void ByteSwap(unsigned char &ch1,unsigned char &ch2)
{
ch1^=ch2;
ch2^=ch1;
ch1^=ch2;
}

// change endianess of float
void ChangeEndianness(float &flt)
{
// get byte pointer
unsigned char *val=reinterpret_cast<unsigned char *>(&flt);

// swap the bytes
ByteSwap(val[0],val[3]);
ByteSwap(val[1],val[2]);
}

Share this post


Link to post
Share on other sites
If speed isn't your biggest concern, you can make a templated function that loops over the bytes of a variable and switches them. Otherwise, you can just define multiple specialized functions for each type you want to apply this to.

Share this post


Link to post
Share on other sites
Quote:
Original post by gregs
or you could be cool:
// the xor byte swap
inline void ByteSwap(unsigned char &ch1,unsigned char &ch2)
{
ch1^=ch2;
ch2^=ch1;
ch1^=ch2;
}

Ah, the xor swap. My favourite premature pessimisation:
#include <ctime>
#include <iostream>

int main()
{
int times[4];
unsigned int x = std::rand();
unsigned int y = std::rand();
int ac[3] = {0, 0, 0};
times[0] = std::clock();
for (unsigned int index = 0; index < 256 * 256 * 256 * 32; ++index)
{
int temp = y;
y = x;
x = temp;
ac[0] += x;
y += x;
}
times[1] = std::clock();
for (unsigned int index = 0; index < 256 * 256 * 256 * 32; ++index)
{
x ^= y ^= x ^= y;
ac[1] += x;
y += x;
}
times[2] = std::clock();
for (unsigned int index = 0; index < 256 * 256 * 256 * 32; ++index)
{

#if defined(__BORLANDC__) || defined(_MSC_VER)
__asm
{
mov eax, x
mov ecx, y
mov x, ecx
mov y, eax
}
#elif defined(__GNUC__)
asm( "mov %0, %%eax;\n\t"
"mov %1, %0;\n\t"
"mov %%eax, %1;"
:"=b"(x), "=c"(y)
:"b"(x), "c"(y)
:"%eax"
);
#endif
ac[2] += x;
y += x;
}
times[3] = std::clock();
std::cout << ac[0] << ", " << ac[1] << ", " << ac[2] << '\n';
std::cout << "tmp: " << (times[1] - times[0]) << '\n';
std::cout << "xor: " << (times[2] - times[1]) << '\n';
std::cout << "asm: " << (times[3] - times[2]) << '\n';
}

> bcc32 -O2 swap.cpp
> swap
-1011529882, -124457220, -1073741824
tmp: 3312
xor: 6047
asm: 3297

> g++ -O3 -oswap.exe swap.cpp
> swap
1872272571, 1624108454, -1348897377
tmp: 609
xor: 812
asm: 1188

> cl /EHsc /O2 swap.cpp
> swap
1872272571, 1624108454, -1348897377
tmp: 1109
xor: 2391
asm: 2843


Enigma

Share this post


Link to post
Share on other sites
You can use your endian-swapping function for 32 bit integers on floats and for 64 bit integers on doubles.

You must use a reinterpret cast, not a normal cast. The problem you are probably experiencing probably has something to do with this.

Here is some example code that I know works. If you are still having problems check other things - like - are you reading in binary or text mode?


uint32 AEndian(uint32 x)
{
return (x>>24)|(x>>8)&0x0000ff00|(x<<8)&0x00ff0000|(x<<24);
}

float32 AEndian(float32 x)
{
uint32 retval = AEndian(reinterpret_cast<uint32>(x));
return reinterpret_cast<float32>(retval);
}

uint64 AEndian(uint64 x)
{
uint64 retval;
((uint32*)&retval)[0] = AEndian(((uint32*)&x)[0]);
((uint32*)&retval)[1] = AEndian(((uint32*)&x)[1]);
return retval;
}

float64 AEndian(float64 x)
{
uint64 retval = AEndian(reinterpret_cast<uint64>(x));
return reinterpret_cast<float64>(retval);
}

Share this post


Link to post
Share on other sites
Something like this perhaps?


template<typename T>
inline void swapBytesOf(T& x) {
swapBytes<sizeof(T)>(reinterpret_cast<char*>(&x));
}

template<size_t count>
inline void swapBytes(char* location) {
std::swap(location, location + count - 1);
swapBytes<count-2>(location+1);
}

template<>
inline void swapBytes<1>(char* location) {}

template<>
inline void swapBytes<0>(char* location) {}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!