0

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;
    }
phuclv
  • 37,963
  • 15
  • 156
  • 475
Jovirus
  • 125
  • 1
  • 11
  • 1
    Hi Jovirus, welcome to StackOverflow. What have you tried so far? What problems have you had with your approach? Questions on StackOverflow will get closed quickly if they don't contain code with a specific problem. – Wai Ha Lee Mar 06 '15 at 14:03
  • possible duplicate of [How to convert IEEE-11073 16-bit SFLOAT to simple float in Java?](http://stackoverflow.com/questions/11564270/how-to-convert-ieee-11073-16-bit-sfloat-to-simple-float-in-java) – Wai Ha Lee Mar 06 '15 at 14:06
  • .. I found the question above, which relates to Java, but you should be able to apply the same principles to C#. – Wai Ha Lee Mar 06 '15 at 14:08
  • @WaiHaLee I solved it and, and put my answer in my question. – Jovirus Mar 11 '15 at 10:27

2 Answers2

3
   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;
}
Jovirus
  • 125
  • 1
  • 11
1

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.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256