0

这篇文章中使用了一个我不明白的方程:

  • 我 = (e + B) * L + m * L

I是解释为整数的浮点数的字节表示。这是一个例子:

float x = 3.5f;
unsigned int i = *((unsigned int *)&x);
  • e是浮点数的指数。
  • B是偏差 (127)。
  • L是一个常数 (1 << 23)。
  • m是尾数。

现在我的问题是:

为什么这个方程是正确的,我在哪里可以阅读更多关于这个方程的信息?

4

2 回答 2

1

如您所知,浮点数存储在 IEEE 754 标准中。单精度浮点的位模式如下(详见此处):

在此处输入图像描述

并且数字的值根据以下公式计算:

在此处输入图像描述

因此,对于 32 位值,等效整数为e * L + m. 因为指数从(第 23 位)开始,第一部分是m. 假设指数与 一起存储-127,则表达式转换为(e + B)*L + m

关于L之后m可能有一个文章中可能没有提到的假设。

此外,sign该公式中不考虑位。

于 2018-01-12T18:53:37.950 回答
1

浮点编码

浮点数用符号s、指数e和有效数f表示。(有些人使用术语“尾数”,但这是对数纸质表格时代的遗留物。浮点值的小数部分首选“有效数”。尾数是对数。有效数是线性的。)二进制浮点,表示的值是 + 2 ef或 - 2 ef,根据符号s

通常对于二进制浮点,有效位需要在 [1, 2) 中,至少对于格式正常范围内的数字。对于编码,第一位与其余位分开,因此我们可以写为f = 1 + r,其中 0 ≤ r < 1。

在 IEEE 754 基本二进制格式中,浮点数被编码为一个符号位、一些指数位和一个有效位字段:

  • 符号s用 0 位表示正数,1 表示负数。由于我们采用对数,因此该数字可能是正数,并且出于当前目的我们可能会忽略符号位。

  • 指数位是实际指数加上一些偏差B。(对于 32 位格式,B是 127。对于 64 位,它是 1023。)

  • 有效字段包含r的位。由于r是分数,因此有效位字段包含以二进制表示的r的位,该位从“二进制点”之后开始。例如,如果r是 5/16,则二进制为“.0101000…”,因此有效数字段包含 0101000…(对于 32 位格式,有效数字段包含 23 位。对于 64 位,52 位。)

b为有效数字段中的位数(23 或 52)。令L为 2 b

那么rL的乘积rL是一个等于有效数字域内容的整数。在我们的示例中,r是 5/16,L是 2 23 = 8,388,608,并且rL = 2,621,440。所以有效数字包含 2,621,440,即 0x280000。

等式I = ( e + B ) • L + mL试图捕捉到这一点。首先,符号被忽略,因为它为零。那么e + B是指数加上偏差。将其乘以L会将其左移b位,这会将其置于浮点编码的指数字段的位置。然后添加rL添加有效位字段的值(为此,我使用r表示“剩余有效位”而不是m表示“尾数”)。

因此,将 2 e • (1+ r )编码为浮点数的位在解释为二进制整数时是 ( e + B ) • L + rL

更多信息

有关 IEEE 754 的信息在WikipediaIEEE 754 标准中。一些以前的 Stack Overflow 答案在此处此处描述了编码格式。

别名/重新解释位

关于您问题中的代码:

float x = 3.5f;
unsigned int i = *((unsigned int *)&x);

不要使用此代码,因为 C 或 C++ 标准未定义其行为。

在 C 中,使用:

#include <string.h>
...
unsigned int i; memcpy(&i, &x, sizeof i);

或者:

unsigned int i = (union { float f; unsigned u; }) { x } .u;

在 C++ 中,使用:

#include <cstring>
...
unsigned int i; std::memcpy(&i, &x, sizeof i);

这些方法被定义为将浮点编码的位重新解释为unsigned int. (当然,它们要求 afloat和 anunsigned int在您使用的 C 或 C++ 实现中具有相同的大小。)

于 2018-01-12T21:15:53.637 回答