将一个 32 位浮点数转换为两个 16 位 uint 数,然后再次转换回该 32 位浮点数

Posted

技术标签:

【中文标题】将一个 32 位浮点数转换为两个 16 位 uint 数,然后再次转换回该 32 位浮点数【英文标题】:Convert one 32bit float number into two 16bit uint number and then convert back to that 32bit float again 【发布时间】:2014-09-24 08:44:13 【问题描述】:

我正在将一个 32 位浮点数从一个平台转移到另一个平台。好吧,它只允许将 16 位 unsinged int 成员传递给传输寄存器。我在想我可以将 32 位浮点数分成两个 16 位,然后再转换为另一侧的 32 位。

(我用的是C语言)

喜欢:

float A = 3.14
uint16_t B = A & 0xffff;
uint16_t C = A & 0xffff0000;

float D = C<<16 & B;

显然这是不正确的,因为浮点数据在分配时将转换为无符号整数。那我平时应该怎么做呢?应该有一些相当成熟的方法来做类似的事情

谢谢

【问题讨论】:

如果您想进一步研究,只需提及一些关键字:这称为类型双关或重新解释。 【参考方案1】:

您可以为此使用联合,例如:

typedef union 
    float f;
    uint16_t a[2];
 U;

U u;

u.f = 3.14f;

printf("%g -> %#x %#x\n", u.f, u.a[0], u.a[1]);

LIVE DEMO

注意:严格来说这是未定义的行为,但它是一种广泛使用的技术,它不太可能失败。或者,您可以采用更安全但可能效率较低的方法,只使用 memcpy,如下所示:

float f = 3.14f;
uint16_t a[2];
memcpy(a, &f, sizeof(a));
printf("%g -> %#x %#x\n", f, a[0], a[1]);

LIVE DEMO

【讨论】:

虽然这是常用的,但读取另一个联合成员而不是写入的联合成员是未定义的行为。 @vlad_tepesch:是的,谢谢,只需在答案中添加一个关于此的注释。 也许更好地使用中间 uint32_t 并手动屏蔽/合并 16 位片段以帮助解决字节顺序差异。毕竟号码是在“平台”之间转移的。 未定义的行为只是一个意外。它是在 C90 中实现定义的,在 C99 中明确未定义,但在 TC3(参见 DR 283)和 C11 中已修复。这里的标准有点模糊(类似的缺陷报告DR 236中有一些链接到委员会的讨论,为什么很难更明确地定义它),但意图很明确,编译器一直支持它。跨度>

以上是关于将一个 32 位浮点数转换为两个 16 位 uint 数,然后再次转换回该 32 位浮点数的主要内容,如果未能解决你的问题,请参考以下文章

SSE 内在函数:将 32 位浮点数转换为 UNSIGNED 8 位整数

浮点数的十六进制表示

32 位到 16 位浮点转换

AVX 将 64 位整数转换为 64 位浮点数

比较一个 32 位浮点数和一个 32 位整数而不强制转换为双精度,当任何一个值都可能太大而无法完全适合另一种类型时

用脚编码音频:将 32 位浮点数转换为 mp3