使用联合操作浮点位:查找适合浮点数的正确 uint 类型

Manipulating float bits using unions: Finding the correct uint type that fits the float

提问人:Hermit 提问时间:11/1/2023 最后编辑:Hermit 更新时间:11/1/2023 访问量:119

问:

在 C 语言中,我看到这段代码被用作操作浮点数的一种方式,直到位:

union {
    uint32_t bits;
    float value;
}

通过定义这种类型的变量,可以在侧面执行按位运算,同时计算浮点值本身,而浮点值本身又可以打印并在表达式中使用。var.bitsvar.value

但是,代码依赖于宽度与大小匹配的事实。虽然通常是这种情况,但我很好奇如何在没有这种假设的情况下实现此代码,即它根据浮点大小选择正确的固定宽度整数。floatunit32_t

我想到的一种方法是使用一堆语句,并通过比较和宽度常量进行分支,例如:ifsizeof(float)stdint.h

if (sizeof(float) == sizeof(uint32_t)) {
    // Define the union with float and uint32_t and do the manipulations ...  
} else if (sizeof(float) == sizeof(uint64_t)) {
    // Define the union with float and uint64_t and do the manipulations ...  
}
else ...

这将起作用,但必须在每个 if 语句中重复代码。我更喜欢在类型声明本身之后全局声明和初始化变量本身,如下所示:

union {
    uint32_t bits;
    float val;
} var = {UINTMAX_C(1)};

因此,该分支需要在预处理级别静态发生,并且在 .sizeof#if

有没有另一种方法可以为浮点数找到正确的固定宽度整数类型?

C 浮点 位操作 并集

评论

2赞 n. m. could be an AI 11/1/2023
人们通常在配置时通过运行一个小的 C 程序来做到这一点,该程序将正确的定义输出为 C 代码片段。
1赞 chux - Reinstate Monica 11/1/2023
迂腐:理论机器可能只有 28 位。并非所有机器都有 8,16,32,64 - 尽管现在这种情况越来越少见。float(u)intN_t
3赞 user694733 11/1/2023
在我看来,您只需要为 .在极少数情况下,断言失败,它将影响您对性能和内存使用情况所做的假设,以及对精度和准确性的假设。这意味着无论如何您都必须查看代码。我花时间试图预测可能永远不会发生的事情是没有意义的。如果断言失败,请在有更多信息可用时担心它。sizeof(uint32_t) == sizeof(float)
1赞 Martin Brown 11/1/2023
有时,将浮点数别名到多个查看方式上会很有帮助。高精度立方根的技巧之一是将双尾数的低 32 位减为零,以便精确计算其平方。假设 IEEE FP 符号位位于相同的顶部位位置,因此我不确定在这里使用 unsigned int 是否有优势。您必须知道浮点数和字节顺序的按位布局才能执行任何有用的操作。我用过的唯一一台具有非常规浮点长度的机器是 CDC 7600(回溯和 60 位)。科学家的理想之选...
1赞 BoP 11/1/2023
如果你还没有用 36 位浮点数测试你的代码,它无论如何都不会在那里工作。因此,静态断言是最佳选择。

答:

1赞 chux - Reinstate Monica 11/1/2023 #1

这不是一个完全有效的解决方案,但是一个开始:根据 .
也许用其他属性进行优化。
floatFLT_XXX

#include <assert.h>
#include <float.h>
#include <stdint.h>

#if FLT_MANT_DIG <= 24 + 2
  typedef uint32_t uint_flt;
#elif FLT_MANT_DIG <= 53 + 4
  typedef uint64_t uint_flt;
#else
  #error TBD code
#endif

// If we got it wrong, stop the compilation.
static_assert(sizeof(float) == sizeof(uint_flt), "TBD code");

请注意,浮点类型,甚至 ,可能是 128 位,并且没有匹配的整数,当然那么宽。float

请注意,FP 和整数技巧的整个过程都受到阻碍,因为两者的字节序肯定不相同。机器就是这样建造的。因此,使用某个整数常量进行初始化并不像人们所希望的那样可移植。union

相反,请重新编写代码以使用字节数组。

union {
    float value;
    unsigned char bits[sizeof(float)];
} x;

使用 here 的此类代码通常表明了实现更高级别编码目标的错误方法。
考虑陈述更高层次的目标。
union

评论

0赞 Lundin 11/1/2023
我认为我们可以放心地假设这一点,如果在同一个 CPU+FPU 上运行,则具有相同的字节数。floatuint32_t
0赞 chux - Reinstate Monica 11/1/2023
@Lundin 安全 - 是的,有点,但是......C 没有指定相同的字节序,并且存在历史反例。IMO,这种混合匹配的字节序使平台成为恐龙,但更好的代码会使用 a 来测试相同的字节序,而不是赤裸裸地假设相同。此外,我仍然想知道OP更高层次的关注。static_assertion()
0赞 Lundin 11/1/2023
C 没有指定它,因为它不是 C 的事。由于 C 没有指定它,因此由应用程序程序员以适当的方式处理它。
0赞 chux - Reinstate Monica 11/1/2023
@Lundin C23/24 正在冒险进入字节序领域,至少在整数方面是这样,使用 .看看一旦它在这里,它是如何发挥作用的。__STDC_ENDIAN_BIG__, __STDC_ENDIAN_LITTLE__, __STDC_ENDIAN_NATIVE__
0赞 Lundin 11/1/2023
这些只是功能,省去了你编写一个小宏来检查它的麻烦 - C 仍然没有规定 CPU 具有哪个字节。 不过,确实提供了各种奇怪的、据说是便携式的功能。stdbit.h