The title speaks for itself: How to convert IEEE-11073 16-bit SFLOAT to simple float in Java?
-
2Can you provide a citation for this format? I'm having difficulty finding a specification. – Louis Wasserman Jul 19 '12 at 15:56
-
1For anyone who's still looking for this spec, it's called "Personal Health Devices Transcoding White Paper" and is available as a PDF from the Bluetooth SIG. This particular type is on page 9. – TheEnigma2112 Jan 06 '14 at 17:58
7 Answers
IEEE-11073 is not in public domain but you can find sufficient 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;
}

- 1,066
- 9
- 17
Even that this post is a little bit old, I just want to post my solution, based on this java file.
public short getExponent(short value)
{
if (value < 0)
{ // if exponent should be negative
return (byte) (((value >> 12) & 0x0F) | 0xF0);
}
return (short) ((value >> 12) & 0x0F);
}
public short getMantissa(short value)
{
if ((value & 0x0800) != 0)
{ // if mantissa should be negative
return (short) ((value & 0x0FFF) | 0xF000);
}
return (short) (value & 0x0FFF);
}
public double parseSFLOATtoDouble(short value)
{
// NaN
if (value == 0x07FF)
{
return Double.NaN;
}
// NRes (not at this resolution)
else if (value == 0x0800)
{
return Double.NaN;
}
// +INF
else if (value == 0x07FE)
{
return Double.POSITIVE_INFINITY;
}
// -INF
else if (value == 0x0802)
{
return Double.NEGATIVE_INFINITY;
}
// Reserved
else if (value == 0x0801)
{
return Double.NaN;
}
else
{
return ((double) getMantissa(value)) * Math.pow(10, getExponent(value));
}
}

- 834
- 2
- 11
- 24
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.

- 525,659
- 79
- 751
- 1,130
-
Do you have an example? Let's say for 69, which are the sign, exponent and mantissa? Thanks a lot! – sunlover3 Dec 27 '16 at 13:26
-
1@sunlover3 The sign is positive, the exponent is 6 for 2^6 and the manitssa is 1.000101 – Peter Lawrey Dec 27 '16 at 18:47
-
1Per the quote in [Petri P’s answer](https://stackoverflow.com/a/14707658/298225), the exponent is for base ten. Merely shifting it for Java’s base-two Number format cannot work. – Eric Postpischil Aug 26 '18 at 12:31
Try searching for "Personal Health Devices Transcoding_WP_V11" and it will lead you to a document from the Bluetooth Special Interest Group. In the 25 Oct 2011 / V11r00 version of the document, section 2.2 "TRANSCODING BLUETOOTH CHARACTERISTICS TO 11073 ATTRIBUTES" gives a detailed explanation and examples of how to deal with 11073-20601 FLOAT (32 bit) and SFLOAT (16 bit) numbers.
The current URL of this document is https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=242961
Note that this is likely the same document Petri P. is referencing above.

- 5,745
- 3
- 25
- 30
-
2This is the new url: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=272346 . Thanks for the information! It helped. – sunlover3 Dec 27 '16 at 13:31
For those looking to convert SFLOAT while using Javascript, here is a neat library, that does that, and more. https://github.com/bluetoother/ble-packet
If you want to add your own characteristics just use addMeta function, defs/charMeta.js has plenty of examples!

- 471
- 4
- 6
I can't find any float specification associated with IEEE 11073, you probably mean a Half precision float (sometimes also called Minifloat).
The format is described sufficiently in Wikipedia to easily convert it into a normal float. Basically, you split it into the 3 fields (sign, exponent, mantissa). The sign does not need conversion, just needs to be shifted to the correct position. Then check the exponent if its MIN or MAX value, handle special cases (Inf, NaN, subnormals/denormalized). Otherwise just correct the bias of the exponent and shift to correct position. For the mantissa, add as many zeros to the right as required. Finally put everything together into an int and use Float.intBitsToFloat(bits) to convert the bits into a normal java float.
Conversion from float works almost the same, only with the additional pitfalls of rounding, overflow and underflow.

- 19,919
- 4
- 36
- 70
-
1That is most of it, presuming the infinity and NaN conversions are handled properly (including the signaling bit of NaNs). However, you also have to handle denormals. When the biased exponent is 0, the significand field is interpreted differently: The implicit bit is 0, not 1. This must be adjusted for, because the adjusted exponent in the 32-bit float will not be zero, so the implicit bit will be 1. One adjustment is to subtract the value of the implicit bit (0x1p-126) from the 32-bit float (if it is positive, add if negative). – Eric Postpischil Jul 19 '12 at 16:31
-
Good point, edited it to mention denormalized numbers. SNaN's shouldn't cause trouble since java supresses signalling. – Durandal Jul 19 '12 at 16:33
-
Per [Petri P’s answer](https://stackoverflow.com/a/14707658/298225), the SFLOAT format uses base ten, and this is not a half-precision float, so merely adjusting a binary exponent cannot work. – Eric Postpischil Aug 26 '18 at 12:36