← 返回 Day 4 正文

Day 4 · 图解

Day 004 — 数字与运算:图解

一图胜千言:用视觉方式理解数字的底层原理。


1. IEEE 754 双精度浮点数的内存布局

64-bit 双精度浮点数布局

符号位 (1 bit)    指数位 (11 bits)        尾数/有效位 (52 bits)
    ↓                  ↓                           ↓
 ┌────┬────────────────┬────────────────────────────────────────────────────────────────────┐
 │ 0  │ 01111111111    │ 1001001000011111101101010100010001000010110100011000                │
 └────┴────────────────┴────────────────────────────────────────────────────────────────────┘
   (-1)^0          2^(1023-1023)=2^0        1 + (二进制小数)
  = +1             = 1                     = 1.5707963267948966...

公式: value = (-1)^s × 2^(e-1023) × (1 + f/2^52)

示例: 数值 π ≈ 3.141592653589793

  位模式: 0 10000000000 1001001000011111101101010100010001000010110100011000
  解析:
  s = 0       → 正数
  e = 1024    → 指数 = 1024 - 1023 = 1
  f = 0x921FB54442D18 → 尾数部分
  value = 1 × 2^1 × 1.5707963267948966...
        = 3.141592653589793...

特殊值编码

指数位全 0 → 非规格化数(非常接近 0 的数值)
  0 00000000000 0000000000000000000000000000000000000000000000000000  = +0
  1 00000000000 0000000000000000000000000000000000000000000000000000  = -0

指数位全 1 + 尾数全 0 → 无穷大
  0 11111111111 0000000000000000000000000000000000000000000000000000  = +inf
  1 11111111111 0000000000000000000000000000000000000000000000000000  = -inf

指数位全 1 + 尾数非 0 → NaN
  0 11111111111 1000000000000000000000000000000000000000000000000000  = NaN

2. 二进制分数:为什么 0.1 不精确

0.1 的二进制表示是无限循环小数:

0.1 × 2 = 0.2 → 取整数 0
0.2 × 2 = 0.4 → 取整数 0
0.4 × 2 = 0.8 → 取整数 0
0.8 × 2 = 1.6 → 取整数 1  ← 余 0.6
0.6 × 2 = 1.2 → 取整数 1  ← 余 0.2 (回到第二步!)
0.2 × 2 = 0.4 → 取整数 0
  ...

0.1 (十进制) = 0.00011001100110011... (二进制,无限循环)
                       ↑   ↑   ↑   循环节 1100
                                    ────
而 0.5 精确:
0.5 × 2 = 1.0 → 取整数 1
0.5 (十进制) = 0.1 (二进制)  ← 精确!

规则:分母只含 2 的质因数才精确
  1/2  = 0.5     ✓ (分母=2)
  1/4  = 0.25    ✓ (分母=4=2²)
  1/8  = 0.125   ✓ (分母=8=2³)
  1/10 = 0.1     ✗ (分母=10=2×5)
  1/3  = 0.333... ✗ (分母=3)

3. 运算符优先级层次结构

          高优先级
             │
        ┌────┴────┐
        │  (...)  │ ← 括号永远最高
        └────┬────┘
             │
        ┌────┴────┐
        │   **    │ ← 幂运算(右结合)
        └────┬────┘
             │
        ┌────┴────┐
        │ +x -x ~x│ ← 一元运算符
        └────┬────┘
             │
        ┌────┴────┐
        │ */ // % │ ← 乘除法
        └────┬────┘
             │
        ┌────┴────┐
        │  + -    │ ← 加减法
        └────┬────┘
             │
        ┌────┴────┐
        │ << >>   │ ← 位移位
        └────┬────┘
             │
        ┌────┴────┐
        │   &     │ ← 位与
        └────┬────┘
             │
        ┌────┴────┐
        │   ^     │ ← 位异或
        └────┬────┘
             │
        ┌────┴────┐
        │   |     │ ← 位或
        └────┬────┘
             │
        ┌────┴────┐
        │ == !=   │ ← 比较运算符
        │ < > <=  │
        │ is in   │
        └────┬────┘
             │
        ┌────┴────┐
        │  not    │ ← 逻辑非
        └────┬────┘
             │
        ┌────┴────┐
        │  and    │ ← 逻辑与
        └────┬────┘
             │
        ┌────┴────┐
        │   or    │ ← 逻辑或
        └────┬────┘
             │
        ┌────┴────┐
        │if-else  │ ← 三元表达式(右结合)
        └────┬────┘
             │
        ┌────┴────┐
        │  :=     │ ← 海象运算符(右结合)
        └─────────┘
             │
          低优先级

4. 位运算真值表与图解

基本位运算真值表

输入 A:  0 0 1 1
输入 B:  0 1 0 1
───────────────
A & B:   0 0 0 1  (AND:全 1 才 1)
A | B:   0 1 1 1  (OR:有 1 就 1)
A ^ B:   0 1 1 0  (XOR:不同才 1)
~A:      1 1 0 0  (NOT:取反)

位运算图解示例

例:mask = 0b1101, value = 0b1010

   ┌───────┐
   │ value │  1 0 1 0
   └───┬───┘
       │
  ┌────┴────┐
  │  AND &  │── 1 0 0 0 → 保留特定位
  └────┬────┘
       │
   ┌───┴───┐
   │ mask  │  1 1 0 1
   └───────┘

   ┌───────┐
   │ value │  1 0 1 0
   └───┬───┘
       │
  ┌────┴────┐
  │  OR  |  │── 1 1 1 1 → 将特定位设为 1
  └────┬────┘
       │
   ┌───┴───┐
   │ mask  │  1 1 0 1
   └───────┘

   ┌───────┐
   │ value │  1 0 1 0
   └───┬───┘
       │
  ┌────┴────┐
  │ XOR ^  │── 0 1 1 1 → 翻转特定位
  └────┬────┘
       │
   ┌───┴───┐
   │ mask  │  1 1 0 1
   └───────┘

位运算实战技巧图解

检查奇偶性 (n & 1):
  n = 5 = 0b101
  n & 1 = 0b101 & 0b001 = 1 → 奇数 ✓

2 的幂检测 (n & (n-1)):
  8   = 1000     16   = 10000
  7   = 0111     15   = 01111
  &   = 0000 ✓   &   = 00000 ✓  (2 的幂)

  6   = 0110     9    = 01001
  5   = 0101     8    = 01000
  &   = 0100 ✗   &   = 01000 ✗  (不是 2 的幂)

取最低位的 1 (n & -n):
  n   =  108 = 01101100
  -n  = -108 = 10010100 (补码)
  &   =    4 = 00000100 ✓ (最低位 1 的值)

5. 类型转换链

隐式类型转换方向(自动提升精度):
   int ──────→ float ──────→ complex
   (bool) ↗

显式类型转换:
   ┌────────────┐
   │ int(x)     │ ← 浮点数: 截断取整
   │            │ ← 字符串: 解析整数
   │            │ ← bool: True→1, False→0
   └────────────┘

   ┌────────────┐
   │ float(x)   │ ← 整数/字符串
   └────────────┘

   ┌────────────┐
   │ complex(r) │ ← 实部,虚部为 0
   │ complex(r,i)│ ← 实部 + 虚部
   └────────────┘

   ┌────────────┐
   │ bool(x)    │ ← 0 / 空 / None → False
   │            │ ← 其他 → True
   └────────────┘

数值 → 字符串:
   str(42)     → "42"
   repr(3.14)  → "3.14"
   bin(42)     → "0b101010"
   oct(42)     → "0o52"
   hex(42)     → "0x2a"
   f"{42:08b}" → "00101010" (格式化: 8位二进制, 补零)

6. 小整数缓存机制

CPython 启动时预创建的整数对象池:

   ┌────┬────┬────┬────┬────┬────┬────┬────┬────┐
   │ -5 │ -4 │ -3 │ -2 │ -1 │  0 │  1 │  2 │  3 │ ...
   └────┴────┴────┴────┴────┴────┴────┴────┴────┘
                                                    ⋮
   ┌────┬────┬────┬────┬────┬────┬────┬────┬────┐
   │250 │251 │252 │253 │254 │255 │256 │    │    │
   └────┴────┴────┴────┴────┴────┴────┴────┴────┘

   - 范围: [-5, 256] 预分配
   - 在此范围内, a is b 总是 True
   - 超出此范围, a is b 可能 False
   - 这只是 CPython 的实现细节,不是语言规范