Как преобразовать 16-битный SFLOAT IEEE-11073 в простой float в Java?
название говорит само за себя: как преобразовать 16-битный SFLOAT IEEE-11073 в простой float в Java?
6 ответов
вы можете использовать сдвиг битов. извлеките знак, экспоненту и мантиссу и сдвиньте их, чтобы они были в формате float. Возможно, вам придется исправить для Infinity и NaN.
Как указывает ответ @PretiP, показатель равен 10, поэтому вам нужно будет умножить или разделить на 10, чтобы получить конечное значение.
IEEE-11073 не является общественным достоянием, но вы можете найти достаточную информацию в профилях личного здоровья bluetooth. Google с полной спецификацией# 11073-2060. Ниже приведена вставка копирования из бумаги транскодирования личного здоровья bluetooth:
следующая информация определена в ISO / IEEE Std. 11073-2060™1-2008 [1]. В SFLOAT-тип тип данных определяется в представляют числовые значения, которые не являются целочисленными по типу. В SFLOAT-тип определяется как 16-разрядное значение с 12-битная мантисса и 4-битный показатель. См. В приложении F. 8 из [1] для тщательного определения SFLOAT-тип. Этот тип данных определяется следующим образом: размер экспоненты мантиссы 4 бит 12 бит
16-битный тип float; целочисленный тип является только заполнителем
SFLOAT-Type :: = INT-U16 16-разрядное значение содержит 4-разрядный показатель база 10, за ней 12-битная мантисса. Каждый по двое-дополнение форма. Специальные значения присваиваются для выражения следующего: NaN [показатель 0, мантисса +(2^11 -1) → 0x07FF] NRes [показатель 0, мантисса –(2^11) → 0x0800] + бесконечность [показатель 0, мантисса +(2^11 -2) → 0x07FE] - бесконечность [показатель 0, мантисса - (2^11 -2) → 0x0802] Зарезервировано для будущего использования [показатель 0, мантисса - (2^11 -1) → 0x0801]
эта библиотека 11073 имеет код C, который делает это:
https://github.com/signove/antidote/blob/master/src/util/bytelib.c
не должно быть трудно преобразовать в 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;
}
шаблонный код:
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;
}
попробуйте найти "личные устройства здоровья Transcoding_WP_V11", и это приведет вас к документу из специальной группы интересов Bluetooth. В версии документа 25 Oct 2011 / V11r00 раздел 2.2 "перекодирование характеристик BLUETOOTH на атрибуты 11073" дает подробное объяснение и примеры того, как обращаться с числами 11073-20601 FLOAT (32 бит) и SFLOAT (16 бит).
текущий URL этого документа есть https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=242961
обратите внимание, что это, вероятно, тот же документ, на который ссылается Петри П.
даже если этот пост немного старый, я просто хочу опубликовать свое решение, основанное на этой файл java.
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));
}
}
Я не могу найти спецификации float, связанные с IEEE 11073, вы наверное означает половину точности с плавающей запятой (иногда также называется Minifloat).
формат достаточно описан в Википедии, чтобы легко преобразовать его в обычный float. В принципе, вы разделяете его на 3 поля (знак, показатель, мантисса). Знак не нуждается в преобразовании, просто нужно сдвинуть в правильное положение. Затем проверьте показатель, если его минимальное или максимальное значение, обрабатывать особые случаи (Inf, NaN, subnormals/denormalized). В противном случае просто исправьте смещение экспоненты и переместитесь в правильное положение. Для мантиссы добавьте столько нулей справа, сколько требуется. Наконец, поместите все вместе в int и используйте Float.intBitsToFloat (bits) для преобразования битов в обычный Java float.
преобразование из float работает почти одинаково, только с дополнительными ловушками округления, переполнения и подтока.