IEEE 浮点表示形式

Microsoft C++ (MSVC) 与 IEEE 数值标准保持一致。 IEEE-754 标准描述浮点格式,这是一种在硬件中表示实数的方法。 浮点数至少有五种在 MSVC 编译器的目标硬件中是可表示的内部格式。 编译器只使用其中两种格式。 MSVC 中使用单精度(4 字节)和双精度(8 字节)格式。 单精度使用关键字 float 进行声明。 双精度使用关键字 double 进行声明。 IEEE 标准还规定了半精度(2 字节)和四倍精度(16 字节)格式以及双扩展精度(10 字节)格式(一些 C 和 C++ 编译器将其作为 long double 数据类型实现)。 在 MSVC 编译器中,long double 数据类型被视为独特的类型,但存储类型映射到 double。 不过,对于使用其他格式(包括硬件支持的双扩展精度格式)的计算,存在固有的汇编语言支持。

这些值按如下格式存储:

存储格式
单精度 (single-precision) 符号位,8 位指数,23 位有效数
双精度 符号位,11 位指数,52 位有效数

在单精度和双精度格式中,假定在小数部分中有前导 1。 小数部分称为“有效数字”(有时亦称为“尾数”)。 这个前导 1 没有存储在内存中,所以有效数字实际上是 24 或 53 位,尽管少存储了 1 位。 扩展双精度格式实际存储此位。

指数的偏差是其可能值的一半。 也就是说,用存储的指数减去此偏差就得到了实际指数。 如果存储的指数小于此偏差,则实际为负指数。

指数偏差如下所示:

指数 偏差
8 位(单精度) 127
11 位(双精度) 1023

这些指数不是 10 的幂;而是 2 的幂。 也就是说,存储的 8 位指数的范围为 -127 到 127,并存储为 0 到 254。 值 2127 大约等于 1038,这是单精度的实际极限。

有效数以 1.XXX... 的形式存储为二进制分数。 此分数的值大于或等于 1 且小于 2。 实数始终以规范化形式存储。 也就是说,有效数字左移,使得有效数字的高阶位始终为 1。 由于此位始终是 1,因此假定采用单精度和双精度格式(但不存储)。 假设二进制(而不是十进制)小数点刚好位于前导 1 的右侧,

浮点的表示格式如下所示:

格式 字节 1 字节 2 字节 3 字节 4 ... 字节 n
单精度 (single-precision) SXXXXXXX XMMMMMMM MMMMMMMM MMMMMMMM
双精度 SXXXXXXX XXXXMMMM MMMMMMMM MMMMMMMM ... MMMMMMMM

S 表示符号位,X 是偏差的指数位,M 是有效数位。 最左边的位假定采用单精度和双精度格式。

若要正确移动二进制小数点,首先要取消指数偏差,然后将二进制小数点向右或向左移动适当的位数。

特殊值

浮点格式包括一些被特殊对待的值。

0 无法规范化,导致它不能以单精度或双精度值的规范化形式表示。 全零的特殊位模式表示 0。 也可以通过设置符号位将 -0 表示为零,但 -0 和 0 的比较结果始终为相等。

无穷大

+∞ 和 −∞ 值由全是 1 的指数和全是 0 的有效数字表示。 正负用符号位表示。

次正规数

可以用规范化形式表示比最小的数更小的数量级。 这些数字称为次规范数或非规范数。 如果指数为全零且有效数不为零,则有效数的隐式前导位被视为 0,而不是 1。 次正规数的精度随有效数中前导零数量的增加而下降。

NaN - 非数

可以使用 IEEE 浮点格式表示不是实数的值(如 0/0)。 这种值称为 NaN。 NaN 由一个全 1 的指数和一个非 0 的有效数表示。 NaN 有两种:quiet NaN (QNaN) 和 signaling NaN (SNaN)。 Quiet NaN 在有效数字中有前导 1,并且通过表达式传播。 它们表示不定值,例如除以无穷大或将无穷大乘以零的结果。 Signaling NaN 在有效数字中有前导 0。 它们用于无效的操作,以发出浮点硬件异常的信号。

示例

以下是单精度格式的一些示例:

  • 对于值 2,符号位为 0。 存储的指数为 128 或二进制的 1000 0000(即 127 + 1)。 存储的二进制有效数为 (1.)000 0000 0000 0000 0000 0000,它具有隐含的前导 1 和二进制小数点,因此实际有效数为 1。

    Formula 二进制表示形式 十六进制
    2 1 * 21 0100 0000 0000 0000 0000 0000 0000 0000 0x40000000
  • 值 -2。 除已设置符号位外,与 +2 相同。 所有 IEEE 格式浮点数的负数也是如此。

    Formula 二进制表示形式 十六进制
    -2 -1 * 21 1100 0000 0000 0000 0000 0000 0000 0000 0xC0000000
  • 值 4。 有效数相同,指数加 1(偏差值为 129,在二进制中为 100 0000 1)。

    公式 二进制表示形式 十六进制
    4 1 * 22 0100 0000 1000 0000 0000 0000 0000 0000 0x40800000
  • 值 6。 指数相同,有效数字要大一半。 它是 (1.)100 0000 ...0000 0000,它是 1 1/2,因为它是小数位的值为 1/2、1/4、1/8 等的二进制分数。

    公式 二进制表示形式 十六进制
    6 1.5 * 22 0100 0000 1100 0000 0000 0000 0000 0000 0x40C00000
  • 值 1。 与 2 的其他幂的有效数相同,偏差指数为 2 的指数减 1,即 127(在二进制中为 011 1111 1)。

    Formula 二进制表示形式 十六进制
    1 1 * 20 0011 1111 1000 0000 0000 0000 0000 0000 0x3F800000
  • 值 0.75。 偏差指数为 126(在二进制中为 011 1111 0),有效数是 (1.)100 0000 ...0000 0000,即 1 1/2。

    Formula 二进制表示形式 十六进制
    0.75 1.5 * 2-1 0011 1111 0100 0000 0000 0000 0000 0000 0x3F400000
  • 值 2.5。 与 2 完全相同,但表示 1/4 的位在有效数中已设置。

    Formula 二进制表示形式 十六进制
    2.5 1.25 * 21 0100 0000 0010 0000 0000 0000 0000 0000 0x40200000
  • 1/10 是二进制中的循环小数。 有效数字略小于 1.6,偏差指数表示 1.6 除以 16。 (二进制数是 011 1101 1,十进制数是 123。)真实指数为 123 - 127 = -4,这意味着乘数因子为 2-4 = 1/16。 存储的有效数字的最后一位进行四舍五入,以尝试尽可能准确地表示不可表示的数字。 (1/10 和 1/100 不能用二进制精确表示的原因类似于 1/3 不能用十进制精确表示的原因。)

    Formula 二进制表示形式 十六进制
    0.1 1.6 * 2-4 0011 1101 1100 1100 1100 1100 1100 1101 0x3DCCCCCD
  • 0 是一个特例。 它使用公式求出可表示的最小正值,即全为 0。

    Formula 二进制表示形式 十六进制
    0 1 * 2-128 0000 0000 0000 0000 0000 0000 0000 0000 0x00000000

另请参阅

为何浮点数可能丢失精度