浮点数作为整数方程的字节表示
Byte representation of float as integer equation
在this文章中使用了一个等式我不明白:
- I = (e + B) * L + m * L
I 是解释为整数的浮点数的字节表示形式。
这是一个例子:
float x = 3.5f;
unsigned int i = *((unsigned int *)&x);
- e 是浮点数的指数。
- B 是偏差 (127).
- L 是常数 (1 << 23).
- m是尾数。
现在我的问题是:
为什么方程是正确的,我在哪里可以阅读更多关于这个方程的信息?
如您所知,浮点数存储在 IEEE 754 标准中。单精度浮点数的位模式如下(详见here):
而数字的值是根据以下公式计算的:
因此,对于 32 位值,等效整数为 e * L + m
。
因为指数是从(第23位)开始的,第一部分是m
。
由于假设指数存储为 -127
,表达式将转换为 (e + B)*L + m
.
关于m
之后的L
可能有一个假设,文中可能没有提到。
此外,sign
位不在该公式中考虑。
浮点编码
浮点数用符号 s、指数 e 和尾数 f 表示。 (有些人使用术语“尾数”,但这是纸质对数表时代遗留下来的。浮点值的小数部分首选“有效数”。尾数是对数的。有效数是线性的。)在二进制浮点数,表示的值为 + 2e • f 或 − 2e • f,根据符号s.
通常对于二进制浮点数,尾数必须在[1, 2),至少对于格式正常范围内的数字是这样。对于编码,第一位与其余位分开,所以我们可以写成 f = 1 + r,其中 0 ≤ r < 1.
在 IEEE 754 基本二进制格式中,浮点数被编码为一个符号位、一些指数位和一个有效数字字段:
符号s编码为0位表示正,1位表示负。由于我们取的是对数,因此这个数字可能是正数,出于当前目的我们可以忽略符号位。
指数位是实际指数加上一些偏差B。 (对于32位格式,B为127。对于64位,为1023。)
signifcand 字段包含 r 的位。由于 r 是分数,因此有效位域包含 r 的位,以二进制表示,从“二进制小数点”开始。例如r为5/16,则二进制为“.0101000…”,则有效位域为0101000…(32位格式,有效位域为23位.对于64位,52位。)
设b 有效数字字段中的位数(23 或52)。设 L 为 2b.
那么r和L的乘积,r • L,是一个等于有效位域内容的整数。在我们的示例中,r 是 5/16,L 是 223 = 8,388,608,并且 r • L = 2,621,440。所以有效数字包含 2,621,440,即 0x280000.
等式I = (e + B) • L + m • L 试图捕获它。首先,符号被忽略,因为它是零。那么 e + B 就是指数加上偏差。将其乘以 L 将其左移 b 位,这将其置于浮点编码的指数字段的位置。然后添加 r • L 添加有效数字字段的值(为此我使用 r 表示“其余的有效数字”而不是 m 表示“尾数”)。
因此,将 2e • (1+r) 编码为当解释为二进制整数时,浮点数是 (e + B) • L + r • L.
更多信息
有关 IEEE 754 的信息在 Wikipedia and the IEEE 754 standard. Some previous Stack Overflow answers describing the encoding format at here and here。
别名/重新解释位
关于您问题中的代码:
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
。 (当然,他们要求 float
和 unsigned int
在您使用的 C 或 C++ 实现中大小相同。)
在this文章中使用了一个等式我不明白:
- I = (e + B) * L + m * L
I 是解释为整数的浮点数的字节表示形式。 这是一个例子:
float x = 3.5f;
unsigned int i = *((unsigned int *)&x);
- e 是浮点数的指数。
- B 是偏差 (127).
- L 是常数 (1 << 23).
- m是尾数。
现在我的问题是:
为什么方程是正确的,我在哪里可以阅读更多关于这个方程的信息?
如您所知,浮点数存储在 IEEE 754 标准中。单精度浮点数的位模式如下(详见here):
而数字的值是根据以下公式计算的:
因此,对于 32 位值,等效整数为 e * L + m
。
因为指数是从(第23位)开始的,第一部分是m
。
由于假设指数存储为 -127
,表达式将转换为 (e + B)*L + m
.
关于m
之后的L
可能有一个假设,文中可能没有提到。
此外,sign
位不在该公式中考虑。
浮点编码
浮点数用符号 s、指数 e 和尾数 f 表示。 (有些人使用术语“尾数”,但这是纸质对数表时代遗留下来的。浮点值的小数部分首选“有效数”。尾数是对数的。有效数是线性的。)在二进制浮点数,表示的值为 + 2e • f 或 − 2e • f,根据符号s.
通常对于二进制浮点数,尾数必须在[1, 2),至少对于格式正常范围内的数字是这样。对于编码,第一位与其余位分开,所以我们可以写成 f = 1 + r,其中 0 ≤ r < 1.
在 IEEE 754 基本二进制格式中,浮点数被编码为一个符号位、一些指数位和一个有效数字字段:
符号s编码为0位表示正,1位表示负。由于我们取的是对数,因此这个数字可能是正数,出于当前目的我们可以忽略符号位。
指数位是实际指数加上一些偏差B。 (对于32位格式,B为127。对于64位,为1023。)
signifcand 字段包含 r 的位。由于 r 是分数,因此有效位域包含 r 的位,以二进制表示,从“二进制小数点”开始。例如r为5/16,则二进制为“.0101000…”,则有效位域为0101000…(32位格式,有效位域为23位.对于64位,52位。)
设b 有效数字字段中的位数(23 或52)。设 L 为 2b.
那么r和L的乘积,r • L,是一个等于有效位域内容的整数。在我们的示例中,r 是 5/16,L 是 223 = 8,388,608,并且 r • L = 2,621,440。所以有效数字包含 2,621,440,即 0x280000.
等式I = (e + B) • L + m • L 试图捕获它。首先,符号被忽略,因为它是零。那么 e + B 就是指数加上偏差。将其乘以 L 将其左移 b 位,这将其置于浮点编码的指数字段的位置。然后添加 r • L 添加有效数字字段的值(为此我使用 r 表示“其余的有效数字”而不是 m 表示“尾数”)。
因此,将 2e • (1+r) 编码为当解释为二进制整数时,浮点数是 (e + B) • L + r • L.
更多信息
有关 IEEE 754 的信息在 Wikipedia and the IEEE 754 standard. Some previous Stack Overflow answers describing the encoding format at here and here。
别名/重新解释位
关于您问题中的代码:
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
。 (当然,他们要求 float
和 unsigned int
在您使用的 C 或 C++ 实现中大小相同。)