Как преобразовать 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 работает почти одинаково, только с дополнительными ловушками округления, переполнения и подтока.