Reputation: 395
I receive a 4-byte long array over BLE and I am interested in converting the last two bytes to a floating point decimal representation(float
, double
, etc) in C#. The original value has the following format:
1 sign bit
4 integer bits
11 fractional bits
My first attempt was using BitConverter
, but I am confused by the procedure.
Example: I receive a byte
array values
where values[2] = 143
and values[3] = 231
. Those 2 bytes combined represent a value in the format specified above. I am not sure, but I think that it would be like this:
SIGN INT FRACTION
0 0000 00000000000
Furthermore, since the value comes in two bytes, I tried to use BitConverter.ToString
to get the hex representation and then concatenate the bytes. It is at this point where I am not sure how to continue.
Thank you for your help!
Upvotes: 3
Views: 1118
Reputation: 186668
Your question lacks information, however the format seems to be clear, e.g. for given two bytes as
byte[] arr = new byte[] { 123, 45 };
we have
01111011 00101101
^^ ^^ .. ^
|| || |
|| |11 fractional bits = 01100101101 (813)
||..|
|4 integer bits = 1111 (15)
|
1 sign bit = 0 (positive)
let's get all the parts:
bool isNegative = (arr[0] & 0b10000000) != 0;
int intPart = (arr[0] & 0b01111000) >> 3;
int fracPart = ((arr[0] & 0b00000111) << 8) | arr[1];
Now we should combine all these parts into a number; here is ambiguity: there are many possible different ways to compute fractional part. One of them is
result = [sign] * (intPart + fracPart / 2**Number_Of_Frac_Bits)
In our case { 123, 45 }
we have
sign = 0 (positive)
intPart = 1111b = 15
fracPart = 01100101101b / (2**11) = 813 / 2048 = 0.39697265625
result = 15.39697265625
Implementation:
// double result = (isNegative ? -1 : 1) * (intPart + fracPart / 2048.0);
Single result = (isNegative ? -1 : 1) * (intPart + fracPart / 2048f);
Console.Write(result);
Outcome:
15.39697
Edit: In case you actually don't have sign bit, but use 2's complement for the integer part (which is unusual - double
, float
use sign bit; 2's complement is for integer types like Int32
, Int16
etc.) I expect just an expectation, 2's complement is unusual in the context) something like
int intPart = (arr[0]) >> 3;
int fracPart = ((arr[0] & 0b00000111) << 8) | arr[1];
if (intPart >= 16)
intPart = -((intPart ^ 0b11111) + 1);
Single result = (intPart + fracPart / 2048f);
Another possibility that you in fact use integer value (Int16
) with fixed floating point; in this case the conversion is easy:
Int16
as usual2048.0
:Code:
// -14.01221 for { 143, 231 }
Single result = unchecked((Int16) ((arr[0] << 8) | arr[1])) / 2048f;
Or
Single result = BitConverter.ToInt16(BitConverter.IsLittleEndian
? arr.Reverse().ToArray()
: arr, 0) / 2048f;
Upvotes: 4