Converting Float Values from Big Endian to Little Endian

Converting float values from big endian to little endian

simply reverse the four bytes works

float ReverseFloat( const float inFloat )
{
float retVal;
char *floatToConvert = ( char* ) & inFloat;
char *returnFloat = ( char* ) & retVal;

// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[3];
returnFloat[1] = floatToConvert[2];
returnFloat[2] = floatToConvert[1];
returnFloat[3] = floatToConvert[0];

return retVal;
}

Converting float values of big endian to little endian using C#

36.0 and 5.832204E-42 are endian-opposites, so this is an endianness problem. On Windows / .NET, you are usually little-endian, so I'm guessing the data is big-endian. That means you need to reverse the data for each value, separately (not the entire array).

To write this in a way that is CPU-safe, the best option is to check BitConverter.IsLittleEndian, and compensate when necessary. For example:

public static float ReadSingleBigEndian(byte[] data, int offset)
{
return ReadSingle(data, offset, false);
}
public static float ReadSingleLittleEndian(byte[] data, int offset)
{
return ReadSingle(data, offset, true);
}
private static float ReadSingle(byte[] data, int offset, bool littleEndian)
{
if (BitConverter.IsLittleEndian != littleEndian)
{ // other-endian; reverse this portion of the data (4 bytes)
byte tmp = data[offset];
data[offset] = data[offset + 3];
data[offset + 3] = tmp;
tmp = data[offset + 1];
data[offset + 1] = data[offset + 2];
data[offset + 2] = tmp;
}
return BitConverter.ToSingle(data, offset);
}

with:

float x= ReadSingleBigEndian(data, 0);
float y= ReadSingleBigEndian(data, 4);
float z= ReadSingleBigEndian(data, 8);
float alpha= ReadSingleBigEndian(data, 12);
float theta= ReadSingleBigEndian(data, 16);
float phi= ReadSingleBigEndian(data, 20);

float to Little Endian Conversion in C#

I think you might be confused because of the way numbers are represented in binary.

Floating-point numbers (in C#) use IEEE 754 to represent them in binary - broadly this is (in big-endian):

{sign}{exponent}{mantissa}.

Integers are more basic than that - a signed integer is represented as:

{sign}(mantissa}.

1234 as a float is 0x449A4000 in big-endian; 0x00409A44 in little-endian.

1234 as an int is 0x000004D2 in big-endian; 0xD2040000 in little-endian (as your result was).


You wouldn't expect 1234 (an int) to have the same binary representation as 1234.0 (a float) because internally, they're stored differently.

If 1234 (as an int) and 1234.0 (a float) had the same binary representation, you'd expect 1235 to differ by one bit in the int representation (it is 0x000004D3 in big-endian; 0xD3040000 in little-endian).

But where does that leave you for 1234.5 (a float)? The closest you could get using the integer representation is 0x000004D2.8 (the .8 is the hex equivalent of .5 in decimal). You can't have a whole binary number between 0x000004D2 and 0x000004D3. That's where floating-point arithmetic comes in - and is why the two differ.

How do I convert between big-endian and little-endian values in C++?

If you're using Visual C++ do the following: You include intrin.h and call the following functions:

For 16 bit numbers:

unsigned short _byteswap_ushort(unsigned short value);

For 32 bit numbers:

unsigned long _byteswap_ulong(unsigned long value);

For 64 bit numbers:

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

8 bit numbers (chars) don't need to be converted.

Also these are only defined for unsigned values they work for signed integers as well.

For floats and doubles it's more difficult as with plain integers as these may or not may be in the host machines byte-order. You can get little-endian floats on big-endian machines and vice versa.

Other compilers have similar intrinsics as well.

In GCC for example you can directly call some builtins as documented here:

uint32_t __builtin_bswap32 (uint32_t x)
uint64_t __builtin_bswap64 (uint64_t x)

(no need to include something). Afaik bits.h declares the same function in a non gcc-centric way as well.

16 bit swap it's just a bit-rotate.

Calling the intrinsics instead of rolling your own gives you the best performance and code density btw..

Floating point Endianness?

Yes, floating point can be endianess dependent. See Converting float values from big endian to little endian for info, be sure to read the comments.

Issues with converting from floating point little-endian to big-endian and back again

I believe you are encountering NaN collapsing. If you really need to distinguish different NaN values you are going to have more problems than just your file storage. According to the Java Language Specification, 4.2.3. Floating-Point Types, Formats, and Values:

IEEE 754 allows multiple distinct NaN values for each of its single
and double floating-point formats. While each hardware architecture
returns a particular bit pattern for NaN when a new NaN is generated,
a programmer can also create NaNs with different bit patterns to
encode, for example, retrospective diagnostic information.

For the most part, the Java SE Platform treats NaN values of a given
type as though collapsed into a single canonical value, and hence this
specification normally refers to an arbitrary NaN as though to a
canonical value.

I asked "Why do you use Float.floatToRawIntBits(raf.readFloat()) rather than raf.readInt()?" because I was trying to understand, and possibly simplify, your test program, not in any expectation of fixing the problem.

How to convert Float to Data with BigEndian?

First create a 32-bit integer with the big-endian representation of the
floating point number, then create a Data value from the integer
(as demonstrated for example in round trip Swift number types to/from Data):

let value = Float(42.13)
var u32be = value.bitPattern.bigEndian
let data = Data(buffer: UnsafeBufferPointer(start: &u32be, count: 1))
print(data as NSData) // <4228851f>

Verify the result by converting it back to a Float:

let v = Float(bitPattern: UInt32(bigEndian: data.withUnsafeBytes { $0.pointee } ))
print(v) // 42.13


Related Topics



Leave a reply



Submit