【问题标题】:Convert a 32 bits to float value将 32 位转换为浮点值
【发布时间】:2012-07-23 11:38:22
【问题描述】:

我正在开发一个 DSP 处理器,以在 Linux 系统上使用 C 实现 BFSK 跳频机制。在程序的接收器部分,我得到一组样本的输入,我使用 Goertzel 算法对其进行解调,以确定接收到的位是 0 还是 1。

现在,我能够单独检测这些位。但是我必须以浮点数组的形式返回数据进行处理。因此,我需要将接收到的每组 32 位打包成一个浮点值。对,我正在做类似的事情:

uint32_t i,j,curBit,curBlk;
unint32_t *outData; //this is intiallized to address of some pre-defined location in DSP memory
float *output;
for(i=0; i<num_os_bits; i++) //Loop for number of data bits
{ 

//Demodulate the data and set curBit=0x0000 or 0x8000

curBlk=curBlk>>1;
curBlk=curBlk|curBit;

bitsCounter+=1;
    if(i!=0 && (bitsCounter%32)==0) //32-bits processed, save the data in array
    {
        *(outData+j)=curBlk;
        j+=1;
        curBlk=0;
    }
}

output=(float *)outData;

现在,output 数组的值就是outData 数组的值,小数点后为 0。 例如:如果output[i]=12345 `outData[i]=12345.0000'。

但是在测试程序时,我正在使用浮点数组生成位的示例测试数据 float data[] ={123.12456,45.789,297.0956};

因此,在解调之后,我希望浮点数组 outputdata 数组具有相同的值。 是否有其他方法可以将 32 位数据转换为浮点数。我是否应该将接收到的位存储到char 数组中,然后将其转换为浮点数。

【问题讨论】:

  • 方法应该是正确的——一点一点,不管你如何使用它。检查转换前后的实际位,这部分应该有。
  • @keltar,我已经匹配了我在发送器部分使用的比特和解调的比特序列。它们相互匹配。因此,我对转换为浮点数组表示怀疑。
  • 你的数组有什么类型完全没有关系(嗯,从技术上讲——只要它是无符号整数类型之一)。它是什么类型的 CPU? (想知道右移 - 大尾数?)。你得到什么样的“不正确”的价值观?不管是什么问题,我不认为它在上面发布的代码中 - 你能制作一个紧凑的工作示例来代表你的问题吗?
  • 我得到的浮点形式的输出是output={17142.000000,16951.000000,17300.000000},与unsigned int array outData={17142,16951,17300}相同。但是,我期望的输出是data[] ={123.12456,45.789,297.0956},因为我用作测试程序输入的位序列是从data[] 数组生成的,并且在基本解调步骤之后得到的位序列是相同的作为测试序列。
  • 如果您试图为 float 和 int 获得相同的数值(或接近),您将需要非常不同的位模式——查看 IEEE 754 标准。如果你想要 32 位精度,你需要使用双精度,而不是浮点数。

标签: c linux embedded


【解决方案1】:

不确定我是否明白你的意思——你顺序获得位,如果你有 32 位,你想从它们中做一个浮点数?

怎么样:

union conv32
{
    uint32_t u32; // here_write_bits
    float    f32; // here_read_float
};

可以这样内联使用:

float f = ((union conv32){.u32 = my_uint}).f32;

或者使用辅助变量:

union conv32 x = {.u32 = my_uint};
float f = x.f32;

【讨论】:

  • 嗨,我试过这个:`typedef union { uint32_t here_write_bits;在这里浮动_read_float; } 测试;测试 t1; t1.here_write_bits=curBlk; \\curBlk 以无符号形式保存 32 位数据 printf("int value 1=%d\n",curBlk); printf("联合的整数值=%d\n", t1.here_write_bits); printf("联合的浮点值=%f\n\n", t1.here_read_float);我得到的输出是:int value 1=17142 int value from union=17142 float value from union=0.000000 这对于我尝试的多个输入是正确的。 union 的 float 部分始终保持为 0。
  • 请注意,尽管联合解决方案在任何地方都可以尝试,但它不受定义的 C 语言支持,因此有一天您可能会发现编译器无法正常工作,而且它不是编译器错误。
  • 与 Clifford 的回答相同的问题:使用 union 会调用未定义的行为。
  • 这工作正常,并且不违反严格的别名。
  • UB 与否,这是musl 使用的方法。如果对他们来说足够好,那么对大多数人来说可能就足够了。
【解决方案2】:

您需要逐字复制位模式而不调用任何隐式转换。最简单的方法是在取消引用之前获取数据的地址并将其重新解释为指向中间“载体”类型的指针。

考虑一下:

float source_float = 1234.5678f ;
uint32_t transport_bits = *((uint32_t*)&source_float);
float destination_float = *((float*)&transport_bits);

transport_bits 中的中间结果取决于目标,在我对 x86 的测试中,它是 0x449a522b,这是该平台上单精度浮点数的位表示(浮点表示和字节序相关)。

无论哪种方式,destination_float 中的结果都与通过uint32_t transport_bits 传输的source_float 相同。

但是,这确实要求发起者的浮点表示与可能不是给定的接收者的浮点表示相同。这有点不可移植,您的代码不起作用的事实可能表明发送者和接收者之间的表示确实不同。不仅FP表示必须相同,而且字节顺序也必须相同。如果它们不同,您的代码可能必须对位进行重新排序并通过提取指数和尾数来计算浮点等效项中的一项或两项。因此,您需要确保位的传输顺序与您重新组装它们的顺序相同。出错的机会很多。

【讨论】:

  • 不幸的是,这会使用严格的别名规则调用未定义的行为。只有两种符合标准的方法可以做到这一点:1. 填充 char 数组并将其指针转换为 float*(严格的别名规则对 char 类型有明确的例外),或 2. 使用 memcpy() .
猜你喜欢
  • 1970-01-01
  • 2011-10-25
  • 2020-05-09
  • 1970-01-01
  • 2010-12-12
  • 2011-03-05
  • 2021-03-26
  • 1970-01-01
相关资源
最近更新 更多