I have a hexadecimal (42 E6 56 00) which should be translated into this float number: 115.2, of course it is float 32 (I've got 115.2 using a calculator). Now I want to perform this operation using C#, I use following code but it gives me strange values:
byte[] bytes = BitConverter.GetBytes(0x42E65600);
if (BitConverter.IsLittleEndian) {
bytes = bytes.Reverse().ToArray();
}
float myFloat = BitConverter.ToSingle(bytes, 0);
The better way to write:
byte[] bytes = new byte[]{ 0x42, 0xE6, 0x56, 0x00 }; // Big endian data
if (BitConverter.IsLittleEndian) {
Array.Reverse(bytes); // Convert big endian to little endian
}
float myFloat = BitConverter.ToSingle(bytes, 0);
Note that BitConverter uses the platform's endianess.
I tested with an IEEE-754 Analysis, it seems that your source data is really big endian, so this is the correct way to write.
You may not know, but BitConverter.GetBytes(0x42E65600); will get byte[]{ 0x00, 0x56, 0xE6, 0x42 } on little endian platform.
If you insists on writing a hexadecimal literal, you don't need to convert the endianess (because it will always be correct, see #George's comment)
byte[] bytes = BitConverter.GetBytes(0x42E65600);
float myFloat = BitConverter.ToSingle(bytes, 0); // Always be correct
I have a hexadecimal (42 E6 56 00) which should be translated into
this float number: 115.2
If that is the case then your data is in big Endian format
BitConverter.IsLittleEndian
This will determine what your bit converted bitness is so you would want the condition to be
if (!BitConverter.IsLittleEndian)
Finally, your endian conversion is wrong. You would not want to reverse the entire array but swap the individual float entries
for (int i = 0; i < data.Length / 2; i++)
{
Swap<byte>(ref data[i], ref data[data.Length - i - 1]);
}
Combining all these rectification, your code should look something like
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
static byte[] Big2Little(byte[] data)
{
for (int i = 0; i < data.Length / 2; i++)
{
Swap<byte>(ref data[i], ref data[data.Length - i - 1]);
}
return data;
}
static void Main(string[] args)
{
byte[] bytes = BitConverter.GetBytes(0x42E65600);
if (!BitConverter.IsLittleEndian)
{
bytes = Big2Little(bytes);
}
float myFloat = BitConverter.ToSingle(bytes, 0);
System.Console.Out.WriteLine(myFloat);
}
Note You can verify your result from the IEEE Analyzer
Related
I am trying to convert these C piece of code into C#. But I've stumble in some parts that I don't understand exactly what is happening, so I am unable to translate it.
void foo(uint64_t *output, uint64_t *input, uint32_t Length){
uint64_t st[25];
memcpy(st, input, Length);
((uint8_t *)st)[Length] = 0x01;
memset(((uint8_t *)st) + Length + 1, 0x00, 128 - Length - 1);
for(int i = 16; i < 25; ++i) st[i] = 0x00UL;
// Last bit of padding
st[16] = 0x8000000000000000UL;
bar(st);
memcpy(output, st, 200);
}
More specifically in the ((uint8_t *)st)[Length] = 0x01; part. I cannot understand the cast/pointer in this line. Why is the * there for? If somebody could explain what is happening, I would be grateful.
What I got so far in C#:
private void foo(ref ulong[] output, ref ulong[] input, uint Length)
{
ulong[] st = new ulong[25];
//memcpy(st, input, Length);
Buffer.BlockCopy(input, 0, st, 0, (int)Length);
// Help in these line please:
//((uint8_t *)st)[Length] = 0x01;
// Still don't know what to do here too:
//memset(((byte)st) + Length + 1, 0x00, 128 - Length - 1);
for (int i = 16; i < 25; ++i)
{
st[i] = 0x00U;
}
// Last bit of padding
st[16] = 0x8000000000000000U;
bar(st);
//memcpy(output, st, 200);
Buffer.BlockCopy(st, 0, output, 0, 200);
}
Thank you.
What your function does is rather primitive memory manipulation:
void foo(uint64_t *output, uint64_t *input, uint32_t Length)
{
uint64_t st[25];
Your function takes a pointer to 16 elements of uint64_t and prepares a local buffer (st) to store a copy of them.
memcpy(st, input, Length);
((uint8_t *)st)[Length] = 0x01;
memset(((uint8_t *)st) + Length + 1, 0x00, 128 - Length - 1);
Make a copy of the input array into st but insert a byte with value 1 at an offset of Length bytes from the start.
for(int i = 16; i < 25; ++i) st[i] = 0x00UL;
The remaining 8 elements of the buffer are cleared to 0. Writing st[16] is pointless as it will be changed again by the next line...
// Last bit of padding
st[16] = 0x8000000000000000UL;
Now we have 16*8 bytes from the input buffer, 1 extra byte with value 1 inserted somewhere and the remaining elements are filled with 1<<63 and lots of 0 bytes.
bar(st);
memcpy(output, st, 200);
}
Do something we have no clue about and copy the resulting 25 elements into the output buffer
I just got confused about how to convert an array of 4 signed bytes to a float number.
I just know for an array of unsigned bytes bts, probably I can use this function
BitConverter.ToSingle(bts, 0);
However, it looks like BitConverter.ToSingle only accepts byte array instead of sbyte array.
Could somebody give me some ideas please?
Thanks!
Maybe this:
float num = 0;
for (int i = 0; i < sbytesArr.Length; i++)
{
num = (num | sbytesArr[i]) << i * 4;
}
Float value = 5000.1234;
//
// Invoke BitConverter.GetBytes to convert double to bytes.
//
byte[] array = BitConverter.GetBytes(value);
foreach (byte element in array)
{
Console.WriteLine(element);
}
//
// You can convert the bytes back to a double.
//
Float result = BitConverter.Tofloat(array, 0);
Console.WriteLine(result);
Assuming that your signed bytes are in an array named sbts you can first of all convert to an unsigned byte array, and then use BitConverter.ToSingle().
byte[] bts = new byte[sbts.Length];
Buffer.BlockCopy(sbts, 0, bts, 0, sbts.Length);
float f = BitConverter.ToSingle(bts, 0);
It is a little known fact that byte and sbyte are interchangeable at the CLR level:
sbyte[] a = new sbyte[1];
byte[] b = (byte[])(object)a;
This code actually works at runtime. So can pass in the array that you have.
BitConverter.ToSingle((byte[])(object)bts, 0);
Call GetFloatValue method passing una array of four sbyte as parameter
public float GetFloatValue(sbyte[] data)
{
return bytesToFloat(data[0], data[1], data[2], data[3]);
}
private static float bytesToFloat(sbyte b0, sbyte b1, sbyte b2, sbyte b3)
{
int mantissa = (byte)b0 + ((byte)b1 << 8) + ((byte)b2 << 16);
return (float)(mantissa * Math.Pow(10, b3));
}
Well, I have a 4 (four) bytes array that I need to convert to double data-type (or float) in C#.
I believe that the 4 bytes array is an OLE Automation one.
Tried the following, but no success:
// 1st trial:
double d = BitConverter.ToDouble(b1, 0); // after resizing b1 to be an 8-byte array and padding with zeroes
// 2nd trial:
Int64 lng = BitConverter.ToInt64(b1, 0); // after resizing b1 to be an 8-byte array and padding with zeroes
double d = BitConverter.Int64BitsToDouble(lng);
// 3rd:
float f = BitConverter.ToSingle(b1, 0); // no resizing, just as is 4-bytes
Tried to reverse the bytes order, but still nothing!
These are sample data:
byte b1 = new byte[] {255, 255, 252, 65};
byte b2 = new byte[] {10, 188, 248, 238};
byte b3 = new byte[] {0, 20, 168, 98};
byte b4 = new byte[] {0, 1, 79, 52};
I also still have this Cpp code that is supposed to do the process:
/*
*********************************************************************************
Simple routine to return four bytes from a buffer (MSB ... LSB) as a double, signed value
*/
double get_four_byte_double(unsigned char *b){
double d;
d = (double)(((((((((unsigned int)b[0])&0xFF)<<8) | ((unsigned int)b[1])&0xFF) << 8) | ((unsigned int)b[2])&0xFF) << 8) | ((unsigned int)b[3])&0xFF);
if (d >= max_thirty_two_bit_integer){
d -= thirty_two_bits;
}
d /= 256.0;
//Return the value we have computed
return(d);
}
Help would be highly appreciated.
Edit:
Values of Cpp thirty_two_bits and max_thirty_two_bit_integer:
static double thirty_two_bits = 65536.0 * 65536.0;
static double max_thirty_two_bit_integer = 65536.0 * 65536.0 / 2.0;
Edit (2):
Unfortunately I can not find the actual values for the sample data, but I am sure they are in the range: 0-7000 or 0-15000.
I need to serialize a bunch of floats and convert to little endian if necessary. I'm aware of BitConverter.GetBytes(float), but I'd rather avoid allocating a ton of little 4-byte arrays on the GC heap. How can I do the conversion into an existing large byte[] array with an offset index? I want something like:
float[] theFloats; // filled up somewhere
byte[] theBytes = new byte[theFloats.Length * 4];
int offset = 0;
for (int i = 0; i < numFloats; ++i)
{
MagicClass.CopyFloatToBytes(theFloats[i], theBytes, offset);
offset += 4;
}
You can create a MemoryStream around the array, then create a BinaryWriter and write floats to it.
Why not just use BitConverter.GetBytes?
You can also do this with [StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Explicit)]
public struct Convert32BitType
{
[FieldOffset(0)]
public int Int32Value;
[FieldOffset(0)]
public float FloatValue;
}
// Example:
var tmp = new Convert32BitType();
tmp.FloatValue = 1.1;
int ival = tmp.Int32Value;
byte b1 = (byte)(ival >> 24);
byte b2 = (byte)(ival >> 16);
byte b3 = (byte)(ival >> 8);
byte b4 = (byte)(ival >> 0);
Another possibility is to used the fixed keyword and cast the pointer, but that requires unsafe code.
I'm reading from a binary stream which is big-endian. The BitConverter class does this automatically. Unfortunately, the floating point conversion I need is not the same as BitConverter.ToSingle(byte[]) so I have my own routine from a co-worker. But the input byte[] needs to be in little-endian. Does anyone have a fast way to convert endianness of a byte[] array. Sure, I could swap each byte but there has got to be a trick. Thanks.
Here is a fast method for changing endianess for singles in a byte array:
public static unsafe void SwapSingles(byte[] data) {
int cnt = data.Length / 4;
fixed (byte* d = data) {
byte* p = d;
while (cnt-- > 0) {
byte a = *p;
p++;
byte b = *p;
*p = *(p + 1);
p++;
*p = b;
p++;
*(p - 3) = *p;
*p = a;
p++;
}
}
}
I use LINQ:
var bytes = new byte[] {0, 0, 0, 1};
var littleEndianBytes = bytes.Reverse().ToArray();
Single x = BitConverter.ToSingle(littleEndianBytes, 0);
You can also .Skip() and .Take() to your heart's content, or else use an index in the BitConverter methods.
What does the routine from your co-worker look like? If it accesses the bytes explicitly, you could change the code (or rather, create a separate method for big-endian data) instead of reversing the bytes.