How to convert IEEE-11073 16-bit SFLOAT to simple float in Java?
IEEE-11073 is not in public domain but you can find suffcient information in bluetooth personal health profiles. Google up with full spec# 11073-2060. Following is copy paste from a bluetooth personal health transcoding paper:
The following information is defined in ISO/IEEE Std. 11073-2060™1-2008 [1]. The SFLOAT-Type data type is defined to represent numeric values that are not integer in type. The SFLOAT-Type is defined as a 16-bit value with 12-bit mantissa and 4-bit exponent. See Annex F.8 of [1] for a thorough definition of the SFLOAT-Type. This data type is defined as follows: Exponent Mantissa Size 4 bit 12 bit
16-bit float type; the integer type is a placeholder only
SFLOAT-Type ::= INT-U16 The 16–bit value contains a 4-bit exponent to base 10, followed by a 12-bit mantissa. Each is in twos-complement form. Special values are assigned to express the following: NaN [exponent 0, mantissa +(2^11 –1) → 0x07FF] NRes [exponent 0, mantissa –(2^11) → 0x0800] + INFINITY [exponent 0, mantissa +(2^11 –2) → 0x07FE] – INFINITY [exponent 0, mantissa –(2^11 –2) → 0x0802] Reserved for future use [exponent 0, mantissa –(2^11 –1) → 0x0801]
This 11073 library has C code that does that:
https://github.com/signove/antidote/blob/master/src/util/bytelib.c
Should not be difficult to convert to Java.
double read_sfloat(ByteStreamReader *stream, int *error)
{
intu16 int_data = read_intu16(stream, error);
if (*error)
return 0;
intu16 mantissa = int_data & 0x0FFF;
int8 expoent = int_data >> 12;
if (expoent >= 0x0008) {
expoent = -((0x000F + 1) - expoent);
}
float output = 0;
if (mantissa >= FIRST_S_RESERVED_VALUE && mantissa
<= MDER_S_NEGATIVE_INFINITY) {
output = reserved_float_values[mantissa
- FIRST_S_RESERVED_VALUE];
} else {
if (mantissa >= 0x0800) {
mantissa = -((0x0FFF + 1) - mantissa);
}
double magnitude = pow(10.0f, expoent);
output = (mantissa * magnitude);
}
return output;
}
The boilerplate code:
typedef enum {
MDER_S_POSITIVE_INFINITY = 0x07FE,
MDER_S_NaN = 0x07FF,
MDER_S_NRes = 0x0800,
MDER_S_RESERVED_VALUE = 0x0801,
MDER_S_NEGATIVE_INFINITY = 0x0802
} ReservedSFloatValues;
static const intu32 FIRST_S_RESERVED_VALUE = MDER_S_POSITIVE_INFINITY;
intu16 read_intu16(ByteStreamReader *stream, int *error)
{
intu16 ret = 0;
if (stream && stream->unread_bytes > 1) {
ret = ntohs(*((uint16_t *) stream->buffer_cur));
stream->buffer_cur += 2;
stream->unread_bytes -= 2;
} else {
if (error) {
*error = 1;
}
ERROR("read_intu16");
}
return ret;
}
You can use bit shifting. extract the sign, exponent and mantissa and shift these so they are in float format. You may need to correct for Infinity and NaN.
As @PretiP's answer points out the exponent is base 10 so you would need to multiply or divide by a power of 10 to get the final value.