# bit 构成

sign、exponent、fraction
符号域、指数域、分数域

  • 32 位:1、8、23
  • 64 位:1、11、52
+------+----------+----------+
| sign | exponent | fraction |
+------+----------+----------+
|  1   |    8     |    23    |   <-- 32 位
+------+----------+----------+
|  1   |    11    |    52    |   <-- 64 位
+------+----------+----------+

# 表示

value=signexponentfractionvalue = sign * exponent * fraction

# sign

  • 0: +
  • 1: -

# exponent

规约形式非规约形式特殊值,含义不一样。

# fraction

规约形式非规约形式特殊值,含义不一样。

# 规约形式

规约形式:1.M2e1.M * 2^e

# 二进制的科学计数法

1.M2e1.M * 2^e

  1. 1.M:把最高位 “1.” 部分隐藏,不在浮点数中表示,称为隐藏位。
    • 因为 “1.” 这部分是固定值,没必要占用空间。
  2. M:保存到 fraction 域中。
    • M 是科学计数法的尾数域(mantissa)。
    • 因为有隐藏位,为了与尾数域区分,M 叫做有效位(significant)。
  3. e:保存到 exponent 中,需要转换为偏正值。
    • exponent=e+biasexponent = e + bias

# exponent

# exponent 范围

exponent(0,2e2]Zexponent \in (0, 2^e - 2] \cap \mathbb{Z}002e12^e - 1 用于特殊值。

  • 32 位(e=8):exponent[1,254]Zexponent \in [1, 254] \cap \mathbb{Z}
  • 64 位(e=11):exponent[1,2046]Zexponent \in [1, 2046] \cap \mathbb{Z}

# 偏正值

exponent 使用 [偏正值] 表示

exponent = 实际指数 + 指数偏移值

  1. 偏正值:引入偏移值,使得 exponent 为正数
  2. 作用:简化比较。指数也有符号,且 S 域也表示符号;如果指数用补码表示,则 (S + EXP) 就不能进行简单的比较

# 指数偏移值 (exponent bias)

2e112^{e-1} - 1

  • 32 位(e=8):+127
  • 64 位(e=11):+1023

# fraction

  1. 保存 1.M 的 M 部分,有效位部分
  2. 范围:1.M[1,2)1.M \in [1, 2)

# 非规约形式

非规约形式:0.M0.M

  1. 使用 0.M 表示
    • 表示非常接近 0:0.M(0,1)0.M \in (0, 1)
    • exponent = 0
    • fraction 保存 M,尾数域(mantissa)
  2. exp = 0, mantissa ≠ 0

# 特殊值

  1. exp=0,mantissa=0exp = 0, mantissa = 0
    • ±0\pm0 (和符号位有关)
  2. exp=2e1,mantissa=0exp = 2^e -1, mantissa = 0
    • ±\pm\infty (和符号位有关)
      • 1.00.0+\frac{1.0}{0.0} \rightarrow +\infty
      • 1.00.0-\frac{1.0}{0.0} \rightarrow -\infty
  3. exp=2e1,mantissa0exp = 2^e -1, mantissa \neq 0
    • NaN (非数,与符号位无关)
      • 0.00.0\frac{0.0}{0.0}
      • 0.0,0.0\infty * 0.0, -\infty * 0.0
      • 1\sqrt{\smash[b]{-1}}
      • 传递性:任何数字与 NaN 的算术运算,结果都是 NaN,除了 NaN0=1NaN^0 = 1
      • 反自反性:v!=vv != v(与自身比较不相等)

# Java 中的浮点数特殊值

浮点数与整数不同,除 0 不会异常。

public static void main(String[] args) {
    float infinity = 1.0f / 0.0f;
    float minusInfinity = -1.0f / 0.0f;
    float NaN = 0.0f / 0.0f;
    System.out.println(infinity);       // Infinity
    System.out.println(minusInfinity);  // - Infinity
    System.out.println(NaN);            // NaN
    System.out.println();
    System.out.println(infinity == infinity);           // true
    System.out.println(minusInfinity == minusInfinity); // true
    System.out.println(NaN == NaN);                     // false
    System.out.println();
    System.out.println(infinity > minusInfinity);   // true
    System.out.println(infinity < minusInfinity);   // false
    System.out.println(NaN > 1);    // false
    System.out.println(NaN < 1);    // false
}