LINUX.ORG.RU

Конвертация SFLOAT в double

 , ,


0

2

Добрый вечер. Пишу кросс-клиент для BTLE железки. Впервые столкнулся с форматом поля SFLOAT.

Кусок из стандарта:

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]

На просторах сети был найден нужный код и немного обрезан под мои нужды:

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 quint32 FIRST_S_RESERVED_VALUE = MDER_S_POSITIVE_INFINITY;

static const double reserved_float_values[5] = {INFINITY, NAN, NAN, NAN, -INFINITY};

double read_sfloat(quint16 int_data)
{
    quint16 mantissa = int_data & 0x0FFF;
    quint8 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;
}

Есть контрольные данные из спека к прибору:

Byte:2 Format:SFLOAT,  LittleEndian
ex.1) 17.6Kpa -> 0xB0, 0xF0
ex.2) 128mmHg -> 0x80, 0x00 


Собственно, вопросы: не совсем понимаю, где ошибка.

Прогонка первого ex. через парсер — результат inf. Второго — 128 OK

Занесение в беззнаковый отрицательного числа выглядит странно:

quint8 expoent = int_data >> 12;
...
expoent = -((0x000F + 1) - expoent);

В вашей ссылке expoent знаковый тип.

mky ★★★★★ ()

Предыдущий оратор всё правильно заметил. Мантисса, кстати, тоже знаковая должна быть.

ex.1) 17.6Kpa -> 0xB0, 0xF0

0xF0 — это минус первая степень, очевидно.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.