解释 C 语言中的浮点数据

Interpreting float data in C

本文关键字:数据 语言 解释      更新时间:2023-10-16

我正在调试缓冲区中出现的数据获得错误值的问题。我正在将缓冲区 ( u8) 类型从内核驱动程序发送到 HAL。在 HAL 中,有一个Uint16缓冲区,它从此缓冲区接收值。

//Code to copy BUFFLEN contents from u8 data[BUFFLEN] into uint16_tData ;
uint16_t uint16_tData[BUFFLEN / 2];
float floatdata[BUFFLEN / 2];

我使用此类型转换从uint16_tData缓冲区获取浮点值:

floatdata[index] = (*((float *)((void *)&uint16_tData[index1];

现在我的问题:如何解释驻留在floatdata数组中的数据?假设我有数据floatdata[0] = 53640;

我如何在floatdata[0]中解释这个半字节中的浮点数据

注意来自 u8 的 4 个字节 -->数组 uint16_tData 的 2 个元素 -->数组浮点数据的一个元素。

我想通过一个例子来了解:

从驱动程序传输的值为:

u8 val1 = 206
u8 val2 = 208
u8 val3 = 120
u8 val4 = 68

在 HAL 中,转换将如何进行,我将在此处获得哪些值?

uint16_tData[0] = ?
uint16_tData[1] = ?

以及如何将数据解释为floatdata中的浮点数?

floatdata[0] = ?
为什么要

这样做?

我想你想要这个:

float *floatdata;
floatdata = (float *)uint16_tData;
// Now use floatdata[index] ...

一次铸造一个物品是愚蠢的。 从uint16_t到浮点的铸造更加愚蠢,最好将其保留为uint8_t(字节),他似乎在其中,或者至少使用uint32_t作为中间。

有什么阻止你这样做的吗? 你能想到如何重新设计你的代码,这样你就可以完全避免处理这些问题吗?

根据我对你的问题的理解,这是你想要的吗

float f ;
uint8_t u8arr[4]={206,208,120,68};
uint16_t arr[2];
memcpy(&arr[0],u8arr,2);
memcpy(&arr[1],u8arr+2,2);
memcpy(&f,arr,4);

uint16"由"2 u8 组成,单精度float为 32 位(4 u8 或 2 uint16),但它们如何"转换"取决于处理这些数据的代码,特别是"发送"的含义(来自内核驱动程序)以及"接收"的代码如何期望数据。我承认我对这个话题一无所知,我现在无法检查和研究它,但我怀疑你有一个字节序问题:你的数据完全具有"意义",而不是单个八位字节,但你把它们放在内存中顺序错误。

基本上,你有一个包含你的八位字节的缓冲区,比如

A   B   C   D
u8  u8  u8  u8      4 u8 arr element (arr[0], arr[1] ...)
____/  ____/  
 uint16   uint16    2 uint16 arr element (arr[0] and arr[1]) 

按照此内存地址递增顺序。如果您希望将A B读取为"正确"的uint16数字,则必须在内存中对其进行"排序",以便匹配处理器的字节序:例如,如果您希望将数字A*8 + B在一个小字节序CPU上,则必须以相反的顺序在内存中写入两个u8:

B A D C

我怀疑 HAL 使用 uint16 只是为了存储数据,而不是将它们解释为 16 位数字,所以这里的字节序不是问题。但是一旦你想从内存中的 4 个 u8(或 2 uint16)获得正确的"浮点数":你必须将 u8 按正确的顺序排列。

如果你想让你的u8被解释为通过铸件浮动,你首先必须将它们放在一个小端机器中,

例如
  address of arr8[0] and arr16[0]
/
D   C   B   A
u8  u8  u8  u8      4 u8 arr element (arr8[0], arr8[1] ...)
____/  ____/  
 uint16   uint16    2 uint16 arr element (arr16[0] and arr16[1]) 

然后,如果你在 litte endian 机器上将这些八位字节"读取"为浮点数,你就有了正确的"浮点数"。

因此,由您来正确排序您的 u8,知道它们将被解释为"宽度"大于一个八位字节的另一种类型。可移植代码应使用正确的方法为具有不同字节序的处理器正确编译。

另请参阅此维基百科文章

我对 HAL/DX 不友好,所以这可能是一个愚蠢的笔记
但是您确定您的浮点数是 16 位而不是 32 位吗?

  • 如果没有,那么每个 2 位浮点数需要 2x16 位 uint,并且错误就在那里。
  • 如果是,请进一步阅读

    1. 转到此处: http://msdn.microsoft.com/en-us/library/Windows/desktop/cc308050(v=vs.85).aspx#alpha_16_bit
    2. 查找 16 位规则
    3. 查找位计数和位置(符号,exp,尾蒂萨)

好的,现在你的问题是什么:

  1. 你有 uint 缓冲区,但将浮点存储在里面?

    • 在这种情况下,只需执行以下操作:

      float16 *p=(float16*)uint16_tData;
      
    • 并使用 p 而不是 uint16_tData
  2. 你有 uint
  3. 缓冲区,里面存储了 uint 值?

    • 这意味着您需要将 uint 转换为浮点
    • 使用内部 = 运算符(如果存在)
    • 如果没有,请编写自己的转换
    • 您可以忽略 uint 的符号
    • 将 exp 设置为 0 (2^0)
    • 将尾数设置为 uint 值
    • 截断未拟合的位
    • 只需向右移动/inc指数,直到uint的MSB适合尾数
    • 将所有位移/和/或放在它们的位置(见上面的链接)
  4. 您有浮点值,需要将它们作为 uint 存储在 uint 中

    • 所以简单地向后做上一点
    • 提取指数,尾数,忽略符号或使用2'os补码
    • 将尾数向左移动指数(如果为正),否则向右移位 -指数
    • 仅此而已。

请注意,在某些平台/编译器/数据类型上,位移也可以插入来自进位或数字另一侧的位移。在这种情况下,结果与位掩码。

不要忘记应用指数偏差!!

希望它有所帮助