little endian float conversion
little endian float conversion
Hello!
I'm wondering if there is a standard macro or function for converting little endian float to big endian, like htonl and ntohs.
If not, how do I convert myself?
I'm wondering if there is a standard macro or function for converting little endian float to big endian, like htonl and ntohs.
If not, how do I convert myself?
Re:little endian float conversion
I've not seen a standard macro I typically use a union when I have to do that kind of conversion...
converting a float to a 'fake' int might look like
and the other direction should be obvious... then you could do something like
to write it, and assuming a function 'funpack', similar but converse to fpack, we could read the float back with
(hopefully I didn't mess anything up too much with that... hope it helps)
-Erik
converting a float to a 'fake' int might look like
Code: Select all
unsigned int
fpack (float f)
{
union
{
float f;
unsigned int i;
} v;
v.f = f;
return v.i;
}
Code: Select all
unsigned int v = htonl(fpack(myfloat));
write(fd, &v, sizeof(unsigned int));
Code: Select all
unsigned int v;
float f;
read(fd, &v, sizeof(unsigned int);
f = funpack(ntohl(v));
-Erik
Re:little endian float conversion
The following seems to be somewhat agreed-upon by what I found on the web.
and
Note that floats do not require conversions, and neither do strings. You also don't need special cases for signed types. 64bit long long would be similar to the above.
It might be worthwhile checking your CPU's instruction set for an appropriate opcode, and use that as inline assembler to improve performance. (Introduces compiler dependency, of course.)
I have seen some much more trickier bit fiddling algorithm in a discussion on Tao's "elate" virtual processor, but forgot to write it down... :-/
Code: Select all
#define conv_short( x ) do { char tmp; \
char * p = (char*) &x; \
tmp = p[0]; \
p[1] = p[0]; \
p[1] = tmp; } while ( 0 )
Code: Select all
#define conv_long( x ) do { char tmp; \
char * p = (char*) &x; \
tmp = p[0]; \
p[0] = p[3]; \
p[3] = tmp; \
tmp = p[1]; \
p[1] = p[2]; \
p[2] = tmp; } while ( 0 )
It might be worthwhile checking your CPU's instruction set for an appropriate opcode, and use that as inline assembler to improve performance. (Introduces compiler dependency, of course.)
I have seen some much more trickier bit fiddling algorithm in a discussion on Tao's "elate" virtual processor, but forgot to write it down... :-/
Code: Select all
Every good solution is obvious once you've found it.
Re:little endian float conversion
What do you mean by "floats do not require conversions"?
The float values I send over the net between machines with the same endian turn up perfectly fine, but when I send between little endian and big endian they get messed up. How can you explain this?
The float values I send over the net between machines with the same endian turn up perfectly fine, but when I send between little endian and big endian they get messed up. How can you explain this?
Re:little endian float conversion
Interesting..
AFAIK, floats are normally stored with the forms defined by that famous IEEE standard.
Are you sure that you are sending and reading the same type of float, that is, either single- or double-precision on both ends?
edit: Also check that you are not relying on any particular calling convention. Floats sometimes get promoted to doubles when passing/returning them to/from functions.
AFAIK, floats are normally stored with the forms defined by that famous IEEE standard.
Are you sure that you are sending and reading the same type of float, that is, either single- or double-precision on both ends?
edit: Also check that you are not relying on any particular calling convention. Floats sometimes get promoted to doubles when passing/returning them to/from functions.
Re:little endian float conversion
[me=Solar]slaps his forehead[/me]
Only now I realized that the whole thread was about floats...
That's right, floats are usually defined by the IEC 60559 / IEEE 754 standard. I'd be hard-pressed to name a mainstream CPU that doesn't adhere to this. They should go without conversion between low and big endian.
Only now I realized that the whole thread was about floats...
That's right, floats are usually defined by the IEC 60559 / IEEE 754 standard. I'd be hard-pressed to name a mainstream CPU that doesn't adhere to this. They should go without conversion between low and big endian.
Every good solution is obvious once you've found it.
Re:little endian float conversion
I've tried to send the value 123.456f over the net, here is what I get:
big endian: 066 246 233 121 (123.456001)
little endian: 152 078 154 068 (123.456055)
As you can see, they're different.
When the big endian machine (a Mac) reads the little endian value it comes up with -0.000000f, and when the little endian machine (Windows) tries to read what the Mac sends, it's 151849983732479890000000000000000000.0f.
I can't see any pattern
big endian: 066 246 233 121 (123.456001)
little endian: 152 078 154 068 (123.456055)
As you can see, they're different.
When the big endian machine (a Mac) reads the little endian value it comes up with -0.000000f, and when the little endian machine (Windows) tries to read what the Mac sends, it's 151849983732479890000000000000000000.0f.
I can't see any pattern
Re:little endian float conversion
The precision of a float is no larger than 6 digits anyway, so from the perspective of a float value, they're equal. The difference in representation is probably due to register - memory - register conversions.ohboy wrote: As you can see, they're different.
So your transmission was successful. Don't scratch your head about the different binary representation.
Every good solution is obvious once you've found it.
Re:little endian float conversion
You got me wrong.
The big endian was when the float was sent between big endian machines.
The little endian was between little endian machines.
little -> big becomes -0.000000f
big -> little becomes 151849983732479890000000000000000000.000000f
The big endian was when the float was sent between big endian machines.
The little endian was between little endian machines.
little -> big becomes -0.000000f
big -> little becomes 151849983732479890000000000000000000.000000f
Re:little endian float conversion
Ah, OK...
(Giving data in octal? Quick, someone fetch Doc Hoggins...)
Let's see. My x86 laptop compiles a float constant of 123.456 to:
0x79 0xe9 0xf6 0x42
This is read from hexdump. A SPARC machine I happen to have access to compiles the same constant to:
0x42 0xF6 0xE9 0x79
Again, this is hexdump output. I am very surprised to see this, as it goes against knowledge ingrained so deep I can't even say where I got it from. Sorry that I gave the (obviously) wrong answer first.
On the upside, looks like you can convert a float just like a 4-byte integer. As to why the two machines you used for testing generated so different code... I'd still suspect register conversions, or the code you used to get the output is borked. Seeing how your numbers don't match mine (reproduced on two machines), I'd say you drew the wrong numbers from your data.
(Giving data in octal? Quick, someone fetch Doc Hoggins...)
Let's see. My x86 laptop compiles a float constant of 123.456 to:
0x79 0xe9 0xf6 0x42
This is read from hexdump. A SPARC machine I happen to have access to compiles the same constant to:
0x42 0xF6 0xE9 0x79
Again, this is hexdump output. I am very surprised to see this, as it goes against knowledge ingrained so deep I can't even say where I got it from. Sorry that I gave the (obviously) wrong answer first.
On the upside, looks like you can convert a float just like a 4-byte integer. As to why the two machines you used for testing generated so different code... I'd still suspect register conversions, or the code you used to get the output is borked. Seeing how your numbers don't match mine (reproduced on two machines), I'd say you drew the wrong numbers from your data.
Every good solution is obvious once you've found it.
Re:little endian float conversion
Yes, it's working now.
I'm converting the float to a u32 by using a union (as erikgreenwald proposed) then I'm just swapping the bytes.
I'm converting the float to a u32 by using a union (as erikgreenwald proposed) then I'm just swapping the bytes.