【问题标题】:Storing ints as floats将整数存储为浮点数
【发布时间】:2010-11-10 23:06:35
【问题描述】:

假设我有一个 API,它只允许我存储浮点数或浮点数数组。但是,我想在这里存储整数值。

我(大致)知道我可以直接投射到 2^23 左右,但如果我想更高怎么办?有什么方法可以让我利用更多的 32 位浮点数,并确保我会得到相同的数字?


澄清:

我正在使用 Pixar 的 PRMan(即 RenderMan)对点云进行一些操作。我可以用 C 或 C++ 编写链接到预编译的点云 API。 PRMan 在任何时候都不必使用我存储的这些整数;我只需要在对附加到点的其他数据进行操作后将它们原封不动地交还给我。

【问题讨论】:

  • 我们在说什么语言?
  • 注意你在哪个平台上了解浮动是如何实现的也很重要。但您使用 IEEE 浮点数可能是一个真正安全的赌注。

标签: c++ c floating-point int


【解决方案1】:

有问题:

在 C 中,您可以执行以下操作,这可能是不安全的(由于严格的别名规则):

int i = XXX;
float f;
*(int *)&f = i;

这依赖于sizeof(int) == sizeof(float)的假设。

问题较少:

更安全,但更冗长的是:

int i = XXX;
float f;
memcpy(&f, &i, sizeof(int));

这仍然依赖于匹配的数据类型大小。但是,以上两种情况都假设您使用的库的内部对数据完全什么。例如,它不会对 NaN 或 +/-infinity 等进行任何特殊处理。

安全:

按照完全不同的思路,如果您愿意为每个 int 浪费两个浮点数,您可以执行以下操作:

int i = XXX;
float f[2] = { (i & 0xFFFF), ((unsigned)i >> 16 };

最后一个是安全的(除了一些关于浮点数和整数大小的相当合理的假设)。

【讨论】:

  • 你不直接用 i >> 16 代表 f[1] 吗?
  • 一些浮点位模式被保留,不能使用。因此,尽管您可以将它们写在内存中浮点变量的顶部,但将它们传递给某种形式的存储可能会以不可预知的方式破坏存储容器。我们没有关于存储的信息,因此不能保证这会起作用。
  • @Martin:是的,我在回答中提到了这一点。
  • @MSN:因为右移负值是实现定义的。
  • 这个方法是错误的,因为它是模棱两可的。例如,数字 32768 和 -32768 都存储为 {32768.0, 0.0}。原因是整数除法是向0舍入,而不是-inf。
【解决方案2】:

尾数字段可让您存储 23 位。指数字段允许您存储几乎 8 位,它是 8 位宽,保留了一些值。还有一个符号位。

避免指数中的保留值,您仍然可以存储您选择的 31 位。

您可能会发现frexpldexp 很有用。

【讨论】:

    【解决方案3】:

    这里给出的所有答案都假设您只想使用为浮点存储保留的字节作为存储 int 的地方。它们不允许您对 int-encoded-in-float 值执行算术运算。如果你想让算术工作,你会遇到 24.99 位(即 -(2^24-1) 到 (2^24-1) 的范围;我认为符号位是 0.99 位而不是 1 位,因为你不能用浮点数的符号/大小表示存储可能的最低值)和一组稀疏的较大值(例如,任何 256 的 32 位整数倍数都可以用浮点数表示)。

    【讨论】:

    • 应该是 24 位,不是吗?单精度有 1 个符号位和 23 个尾数位。
    猜你喜欢
    • 1970-01-01
    • 2019-10-17
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多