【问题标题】:Float bitwise ops浮点按位运算
【发布时间】:2011-07-17 10:03:41
【问题描述】:

我想将浮点数的存储转换为整数('number'值不需要相等)。

如果一个浮点数(例如 10),用二进制表示(至少在我的实现中)为:

01000001001000000000000000000000

那么它应该(也在我的实现中)表示整数值 1092616192。

我目前正在通过以下方式进行此操作:

union UNFI {
    float a;
    int b;
};

UNFI n;
n.a = 10;
int bits = n.b; // foo!

for (int i=31; i>=0; --i) {
    bool bit = ((bits >> i) & 1);
    std::cout << bit;
}

这实现了我想要的,但它本质上是未定义的行为。因此,我想知道实现这一结果的“正确”方式是什么。

来自 C99 标准:

With one exception, if the value of a member of a union object is used when the most recent store to the object was to a different member,the behavior is implementation-defined.

这不是未定义的行为吗?

【问题讨论】:

  • 你想要达到的结果是什么?只是输出浮点数的二进制表示?
  • 部分的主要目的是将二进制文件从浮点数转换为整数数据类型;反之亦然(取决于解决方案的复杂性)。
  • 你所说的“正确方式”是什么意思?你的意思是“跨平台”?很难理解您的问题。
  • @Daniel 为什么不简单地进行正常的 float->int 转换?你想实现什么不同?
  • 我已经概述了这一点,我不想做演员表。我不关心有问题的实际数据类型,只关心存储在内存中的位。

标签: c++ floating-point integer bitwise-operators


【解决方案1】:

您所追求的是简单类型的软管。你正在做的似乎是最简单的事情。我想另一种选择是指针转换。

int const bits = *(reinterpret_cast<int *>(&n))

【讨论】:

  • 这是未定义的行为(非法类型双关语)。它对优化器造成严重破坏。
  • @Ben Voigt- 有趣。我必须在设备驱动程序中做很多这样的事情(通常从无符号数组转换为浮点数组)。将n 声明为volatile 会帮助优化器解决问题吗?
  • 我不这么认为。在 gcc 中,您可以使用-fno-strict-aliasing,代价是阻止基于这些假设的任何优化。此外,您不能 static_cast 指向不相关类型的指针,例如 float 和 int。
  • reinterpret_cast 修复了编译错误,但仍然是 UB。
【解决方案2】:

正确的方法是拨打memcpy。大多数编译器会像联合一样将其优化为有效的单字内存访问,但在具有额外对齐要求的平台上,它们会做正确的事情。而且它永远不会触发信号 NaN。

float a = 10;

char bits[sizeof a];
memcpy(bits, &a, sizeof a);

int b;
static_assert(sizeof b == sizeof a);
memcpy(&b, &a, sizeof a);

【讨论】:

  • @Ben Voigt 如果 NaN 结果在寄存器中并且必须先复制到 a 才能成为 memcpy d,这会导致 NaN 信号吗?从浮点寄存器中读取)?
  • memcpy 是一个遗留的 C 库例程。我并不反对你,但似乎应该有一种更 C++ 的方式来做到这一点......
  • @T.E.D:为什么?这 低级 C 代码,具体到位! C++ 不做那种事情。
  • @Mark B:也许,但您首先需要在 FPU 寄存器中发送信号 NaN。如果启用,到达那里会产生一个信号。此外,FP 寄存器溢出逻辑上是早期分配的一部分。虽然你说的可能是汇编指令,但我认为C++编译器在改变FPU异常模式后无法重新排序溢出,所以如果有注册的SNaN,FPU信号必须关闭。
  • @T.E.D.:C 方式:#include &lt;stdlib.h&gt; 更多 C++ 方式:#include &lt;cstdlib&gt; 现在开心吗? (std::copy 不是memcpy 的替代品,它是memcpy 的类型安全用法的替代品,但事实并非如此)。
【解决方案3】:

什么是未定义的?
IEEE float 的布局非常明确,唯一额外的复杂因素是您平台上的字节顺序(以及 int 有多大)

【讨论】:

  • 来自 C99 标准:“除了一个例外,如果联合对象的成员的值在对象的最新存储是不同的成员时使用,则行为是实现定义的”。这不是未定义的行为吗?
  • 或者它只是“实现定义的”,因此假设我从不期望 int 在数值方面是 == float,我应该没问题?
  • @Daniel:如果您使用 C++ 编程,为什么要阅读 C99 标准? C++ 不是 C99 的超集,在很多情况下行为是不同的。
  • 当然,但是我上次处理类似问题时只是来自 C,因此也许您可以指出正确的答案(或至少参考它),这样我就可以继续我的快乐方式.
  • 我很确定它实际上在 C++ 中也是未定义的,但它是大多数/所有编译器以显而易见的方式实现的未定义行为。
猜你喜欢
  • 2015-05-25
  • 2010-12-15
  • 2017-06-17
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 1970-01-01
  • 2016-08-23
相关资源
最近更新 更多