I need to convert a two byte array to SFloat format according to IEEE-11073.
How can I do that?
I answer my question here.
public float ToSFloat(byte[] value)
{
if (value.Length != 2)
throw new ArgumentException();
byte b0 = value[0];
byte b1 = value[1];
var mantissa = unsignedToSigned(ToInt(b0) + ((ToInt(b1) & 0x0F) << 8), 12);
var exponent = unsignedToSigned(ToInt(b1) >> 4, 4);
return (float)(mantissa * Math.Pow(10, exponent));
}
public int ToInt(byte value)
{
return value & 0xFF;
}
private int unsignedToSigned(int unsigned, int size)
{
if ((unsigned & (1 << size-1)) != 0)
{
unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1)));
}
return unsigned;
}
public float ToSFloat(byte[] value)
{
if (value.Length != 2)
throw new ArgumentException();
byte b0 = value[0];
byte b1 = value[1];
var mantissa = unsignedToSigned(ToInt(b0) + ((ToInt(b1) & 0x0F) << 8), 12);
var exponent = unsignedToSigned(ToInt(b1) >> 4, 4);
return (float)(mantissa * Math.Pow(10, exponent));
}
public int ToInt(byte value)
{
return value & 0xFF;
}
private int unsignedToSigned(int unsigned, int size)
{
if ((unsigned & (1 << size-1)) != 0)
{
unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1)));
}
return unsigned;
}
Loosely based on the C implementation by Signove on GitHub I have created this function in C#:
Dictionary<Int32, Single> reservedValues = new Dictionary<Int32, Single> {
{ 0x07FE, Single.PositiveInfinity },
{ 0x07FF, Single.NaN },
{ 0x0800, Single.NaN },
{ 0x0801, Single.NaN },
{ 0x0802, Single.NegativeInfinity }
};
Single Ieee11073ToSingle(Byte[] bytes) {
var ieee11073 = (UInt16) (bytes[0] + 0x100*bytes[1]);
var mantissa = ieee11073 & 0x0FFF;
if (reservedValues.ContainsKey(mantissa))
return reservedValues[mantissa];
if (mantissa >= 0x0800)
mantissa = -(0x1000 - mantissa);
var exponent = ieee11073 >> 12;
if (exponent >= 0x08)
exponent = -(0x10 - exponent);
var magnitude = Math.Pow(10d, exponent);
return (Single) (mantissa*magnitude);
}
This function assumes that the bytes are in little endian format. If not you will have to swap bytes[0] and bytes[1] in the first line of the function. Or perhaps even better remove the first line from the function and change the function argument to accept a UInt16 (the IEEE 11073 value) and then let the caller decide how to extract this value from the input.
I highly advise you to test this code because I do not have any test values to verify the correctnes of the conversion.
Related
I have an array of ushorts and want to iterate over the array and check if the first two bits of that ushort are 11 if so I want to clear them. However the bit mask I am using to read the first two bits in my conditional are not working properly and the if statement does not trigger when the first two bits are 11
static public void trimData(ushort[] rawData)
{
for(int i = 0; i < rawData.Length; i++)
{
if (((ushort)(rawData[i] & (1 << 15)) == 1) && ((ushort)(rawData[i] & (1 << 14)) == 1))
{
rawData[i] = (ushort)(rawData[i]&~(1<<15));
rawData[i] = (ushort)(rawData[i]&~(1<<14));
}
}
}
How can I use bitmasks to do this correctly?
You can shift these bits to have them being the rightmost ones and then mask with 0b11:
// drop all bits except topmost ones 16 - 14 == 2 which are now the rightmost
int bits = (rawData[i] >> 14) & 0b11;
if (bits == 0b11) {
// Both bits are set
}
To clear these bits you use XOR ^ (since 1 ^ 1 == 0):
int mask = 0b11 << 14;
// remove 14th and 15th set bits
rawData[i] = (ushort)(rawData[i] ^ mask);
Let's combine these parts:
if (((rawData[i] >> 14) & 0b11) == 0b11)
rawData[i] = (ushort)(rawData[i] ^ (0b11 << 14));
Finally, the method can be
public static void trimData(ushort[] rawData) {
if (rawData is null)
throw new ArgumentNullException(nameof(rawData));
for (int i = 0; i < rawData.Length; i++)
if (((rawData[i] >> 14) & 0b11) == 0b11)
rawData[i] = (ushort)(rawData[i] ^ (0b11 << 14));
}
Can you try this?
static public void trimData(ushort[] rawData)
{
for(int i = 0; i < rawData.Length; i++)
{
if (49152 == (49152 & rawData[i]))
{
rawData = rawData.Where(x=>x != rawData[i]).ToArray();
}
}
}
49152 = (2^14) + (2^15)
I have one byte of data and from there I have to extract it in the following manner.
data[0] has to extract
id(5 bit)
Sequence(2 bit)
HashAppData(1 bit)
data[1] has to extract
id(6 bit)
offset(2 bit)
Required functions are below where byte array length is 2 and I have to extract to the above manner.
public static int ParseData(byte[] data)
{
// All code goes here
}
Couldn't find any suitable solution to how do I make it. Can you please extract it?
EDIT: Fragment datatype should be in Integer
Something like this?
int id = (data[0] >> 3) & 31;
int sequence = (data[0] >> 1) & 3;
int hashAppData = data[0] & 1;
int id2 = (data[1] >> 2) & 63;
int offset = data[1] & 3;
This is how I'd do it for the first byte:
byte value = 155;
byte maskForHighest5 = 128+64+32+16+8;
byte maskForNext2 = 4+2;
byte maskForLast = 1;
byte result1 = (byte)((value & maskForHighest5) >> 3); // shift right 3 bits
byte result2 = (byte)((value & maskForNext2) >> 1); // shift right 1 bit
byte result3 = (byte)(value & maskForLast);
Working demo (.NET Fiddle):
https://dotnetfiddle.net/lNZ9TR
Code for the 2nd byte will be very similar.
If you're uncomfortable with bit manipulation, use an extension method to keep the intent of ParseData clear. This extension can be adapted for other integers by replacing both uses of byte with the necessary type.
public static int GetBitValue(this byte b, int offset, int length)
{
const int ByteWidth = sizeof(byte) * 8;
// System.Diagnostics validation - Excluded in release builds
Debug.Assert(offset >= 0);
Debug.Assert(offset < ByteWidth);
Debug.Assert(length > 0);
Debug.Assert(length <= ByteWidth);
Debug.Assert(offset + length <= ByteWidth);
var shift = ByteWidth - offset - length;
var mask = (1 << length) - 1;
return (b >> shift) & mask;
}
Usage in this case:
public static int ParseData(byte[] data)
{
{ // data[0]
var id = data[0].GetBitValue(0, 5);
var sequence = data[0].GetBitValue(5, 2);
var hashAppData = data[0].GetBitValue(7, 1);
}
{ // data[1]
var id = data[1].GetBitValue(0, 6);
var offset = data[1].GetBitValue(6, 2);
}
// ... return necessary data
}
To convert a byte[] to an int, I would normally use BitConverter.ToInt32, but I'm currently working within a framework called UdonSharp that restricts access to most System methods, so I'm unable to use that helper function. I was able to do the reverse operation manually (converting int to byte[]) quite easily like so:
private byte[] GetBytes(int target)
{
byte[] bytes = new byte[4];
bytes[0] = (byte)(target >> 24);
bytes[1] = (byte)(target >> 16);
bytes[2] = (byte)(target >> 8);
bytes[3] = (byte)target;
return bytes;
}
But I'm struggling to get it working the other way around. Would greatly appreciate any help!
You can check the code here: https://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs
#if BIGENDIAN
public static readonly bool IsLittleEndian /* = false */;
#else
public static readonly bool IsLittleEndian = true;
#endif
[System.Security.SecuritySafeCritical] // auto-generated
public static unsafe int ToInt32(byte[] value, int startIndex) {
if (value == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
}
if ((uint) startIndex >= value.Length) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
}
if (startIndex > value.Length - 4) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
}
Contract.EndContractBlock();
fixed(byte * pbyte = & value[startIndex]) {
if (startIndex % 4 == 0) { // data is aligned
return *((int * ) pbyte);
} else {
if (IsLittleEndian) {
return ( * pbyte) | ( * (pbyte + 1) << 8) | ( * (pbyte + 2) << 16) | ( * (pbyte + 3) << 24);
} else {
return ( * pbyte << 24) | ( * (pbyte + 1) << 16) | ( * (pbyte + 2) << 8) | ( * (pbyte + 3));
}
}
}
}
The below code is simple converting a 32bit-integer from the object being passed to the function, the 32-bit integer represents a floating number. I have checked with an online calculator that that i am getting the sign, exponent and mantessa the correct way but strangely i am getting the answer wrong.
Can anyone please check if i am mathematically (or maybe programmatically) doing it wrong somehow!?
Regards
public double FromFloatSafe(object f)
{
uint fb = Convert.ToUInt32(f);
uint sign, exponent = 0, mantessa = 0;
uint bias = 127;
sign = (fb >> 31) & 1;
exponent = (fb >> 23) & 0xFF;
mantessa = (fb & 0x7FFFFF);
double fSign = Math.Pow((-1), sign);
double fMantessa = 1 + (1 / mantessa);
double fExponent = Math.Pow(2, (exponent -bias));
double ret = fSign * fMantessa * fExponent;
return ret;
}
Something like that:
uint fb = Convert.ToUInt32(f);
return BitConverter.ToSingle(BitConverter.GetBytes((int) fb), 0);
This handles even denormal numbers:
public static float FromFloatSafe(object f)
{
uint fb = Convert.ToUInt32(f);
int sign = (int)((fb >> 31) & 1);
int exponent = (int)((fb >> 23) & 0xFF);
int mantissa = (int)(fb & 0x7FFFFF);
float fMantissa;
float fSign = sign == 0 ? 1.0f : -1.0f;
if (exponent != 0)
{
exponent -= 127;
fMantissa = 1.0f + (mantissa / (float)0x800000);
}
else
{
if (mantissa != 0)
{
// denormal
exponent -= 126;
fMantissa = 1.0f / (float)0x800000;
}
else
{
// +0 and -0 cases
fMantissa = 0;
}
}
float fExponent = (float)Math.Pow(2.0, exponent);
float ret = fSign * fMantissa * fExponent;
return ret;
}
note that I do think there is something fishy here, but you asked for it, I wrote it... I feel this is a XY problem.
Ah... and note that while academically what I wrote is very interesting, I normally do it this way:
[StructLayout(LayoutKind.Explicit)]
public struct UInt32ToFloat
{
[FieldOffset(0)]
public uint UInt32;
[FieldOffset(0)]
public float Single;
}
then
float f = new UInt32ToFloat { UInt32 = Convert.ToUInt32(f) }.Single;
I'm trying to extend this topic a bit by expanding it to cover 5-bit values packed into a byte[] data structure.
The specific objective I'm trying to achieve would be to store a total of 128 5-bit (0-31) numeric values in a 80-byte array with a get/set function to access and manipulate the values within the array.
Does anyone have experience with this?
Edit:
Thanks to Guffa in the accepted answer below, here's an inline version of his class for use in static calls:
byte Get_5_In_BA(ref byte[] storage, int index)
{
int bigIndex = (index * 5) / 8;
int smallIndex = (index * 5) % 8;
if (smallIndex > 3)
{
return ((byte) (((storage[bigIndex] + (storage[bigIndex + 1] * 0x0100)) >> smallIndex) & 0x1F));
}
return ((byte) ((storage[bigIndex] >> smallIndex) & 0x1F));
}
void Set_5_In_BA(ref byte[] storage, int index, byte value)
{
if (value > 31) { value = 31; }
int bigIndex = (index * 5) / 8;
int smallIndex = (index * 5) % 8;
int mask = 0x1F << smallIndex;
storage[bigIndex] = (byte) ((storage[bigIndex] & ~mask) | (value << smallIndex));
if (smallIndex > 3)
{
storage[bigIndex + 1] = (byte) ((storage[bigIndex + 1] & ~(mask >> 8)) | (value >> (8 - smallIndex)));
}
}
Something like this should do it:
public class FiveBit {
private byte[] _data;
public FiveBit(int len) {
_data = new byte[(len * 5 + 7) / 8];
}
public int this[int index] {
get {
int i = index * 5 / 8;
int ofs = index * 5 % 8;
if (ofs > 3) {
return ((_data[i] + _data[i + 1] * 256) >> ofs) & 31;
} else {
return (_data[i] >> ofs) & 31;
}
}
set {
int i = index * 5 / 8;
int ofs = index * 5 % 8;
int mask = 31 << ofs;
_data[i] = (byte)((_data[i] & ~mask) | (value << ofs));
if (ofs > 3) {
_data[i + 1] = (byte)((_data[i + 1] & ~(mask >> 8)) | (value >> (8 - ofs)));
}
}
}
}
Note: This is not throroughly tested, but I have tested that I can put 128 random 5-bit values in it, and get the same values out again. You should also add some range checks on the parameters to make the code more robust, and I didn't give much thought to the class name so you can surely make up something that describes it better.