6

标题不言自明:如何将 IEEE-11073 16 位 SFLOAT 转换为 Java 中的简单浮点数?

4

7 回答 7

7

IEEE-11073 不在公共领域,但您可以在蓝牙个人健康档案中找到足够的信息。谷歌完整规范#11073-2060。以下是蓝牙个人健康转码纸的复制粘贴:

以下信息在 ISO/IEEE 标准中定义。11073-2060™1-2008 [1]。SFLOAT-Type 数据类型被定义为表示非整数类型的数值。SFLOAT-Type 定义为具有 12 位尾数和 4 位指数的 16 位值。有关 SFLOAT 类型的详细定义,请参见 [1] 的附录 F.8。该数据类型定义如下: 指数尾数大小 4 位 12 位

16位浮点型;整数类型只是占位符

SFLOAT-Type ::= INT-U16 16 位值包含以 10 为底的 4 位指数,后跟 12 位尾数。每个都是二进制补码形式。分配特殊值以表示以下内容: NaN [指数 0,尾数 +(2^11 –1) → 0x07FF] NRes [指数 0,尾数 –(2^11) → 0x0800] + INFINITY [指数 0,尾数 +( 2^11 –2) → 0x07FE] – INFINITY [指数 0,尾数 –(2^11 –2) → 0x0802] 保留供将来使用 [指数 0,尾数 –(2^11 –1) → 0x0801]

于 2013-02-05T12:32:51.383 回答
7

这个 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;
}
于 2013-05-10T03:57:05.590 回答
2

您可以使用位移。提取符号、指数和尾数并将它们移位,使它们为浮点格式。您可能需要更正 Infinity 和 NaN。

正如@PretiP 的回答所指出的那样,指数以 10 为底,因此您需要乘以或除以 10 的幂才能得到最终值。

于 2012-07-19T15:45:47.223 回答
2

尝试搜索“Personal Health Devices Transcoding_WP_V11”,它将引导您找到来自蓝牙特别兴趣小组的文档。在 2011 年 10 月 25 日/V11r00 版本的文档中,第 2.2 节“将蓝牙特性转码为 11073 属性”给出了如何处理 11073-20601 FLOAT(32 位)和 SFLOAT(16 位)数字的详细说明和示例。

本文档的当前 URL 为 https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=242961

请注意,这可能与 Petri P. 上面引用的文件相同。

于 2013-09-04T15:03:24.007 回答
2

即使这篇文章有点旧,我只想发布我的解决方案,基于这个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));
    }
}
于 2016-01-20T17:17:16.107 回答
0

对于那些希望在使用 Javascript 时转换 SFLOAT 的人来说,这里有一个简洁的库,可以做到这一点,等等。 https://github.com/bluetoother/ble-packet

如果你想添加自己的特性,只需使用 addMeta 函数,defs/charMeta.js 有很多例子!

于 2020-03-03T17:09:03.613 回答
-2

我找不到任何与 IEEE 11073 相关的浮点规范,您可能是指半精度浮点(有时也称为 Minifloat)。

该格式在 Wikipedia 中有充分的描述,可以轻松地将其转换为普通浮点数。基本上,您将其分为 3 个字段(符号、指数、尾数)。标志不需要转换,只需要移动到正确的位置。然后检查指数是否为 MIN 或 MAX 值,处理特殊情况(Inf、NaN、次正规/非正规化)。否则,只需纠正指数的偏差并转移到正确的位置。对于尾数,根据需要在右侧添加尽可能多的零。最后将所有内容放在一个 int 中,并使用 Float.intBitsToFloat(bits) 将这些位转换为普通的 java 浮点数。

从浮点数转换的工作方式几乎相同,只是存在舍入、上溢和下溢的额外陷阱。

于 2012-07-19T16:14:16.987 回答