整数用有限位表示(原码/反码/补码),实数用二进制逼近(IEEE 754)——决定第 3 章 ALU 与 C 的 unsigned/浮点陷阱。
一切进制都是位权展开:任意 R 进制数 d_n…d_1d_0 的值 = Σ d_i × R^i。
1010 1110 = 0xAE——一字节正好两个十六进制位。0.1 转二进制是无限循环小数 0.0001100110011…,计算机里无法精确表示——浮点误差源头(见 2.4)。注意:二进制表示十进制小数不保证精确;但二进制↔十六进制是 2 的幂次换算,纯位分组、无损无舍入。
负数三种表示法(8 位 -5):
| 表示 | -5 的编码 | 正数区 | 零的表示 | 关键性质 |
|---|---|---|---|---|
| 原码 | 1000 0101 | 最高位是符号 | 0000 0000 和 1000 0000 两个零 | 人读直观,但加减法要判符号,硬件复杂 |
| 反码 | 1111 1010 | 按位取反 | 两个零 | 减法仍要处理「循环进位」,未根本解决 |
| 补码 | 1111 1011 | 反码+1 | 只有一个零 | 减法=加法,硬件只需加法器 |
补码是唯一正确解:
+0/-0 两零,浪费编码且比较要特判;补码零唯一,1000 0000 解放为 -128,8 位范围 -128~+127。-x ≡ 2ⁿ-x (mod 2ⁿ),A-B = A+(2ⁿ-B) 溢出位自然丢弃,硬件无需减法器。对比:
-x补码 = 取反加一(反向-(-x)=x也成立)。机器捷径:从右往左找第一个 1,其左全取反、其右不动——-5原码0000 0101→ 左0000 010取反1111 101,拼右1=1111 1011。
求 -5 的补码(8 位):
+5 = 0000 0101
取反 = 1111 1010
加一 = 1111 1011 ← -5
定点数:小数点位置固定(整数是小数点在最右端的特例)。溢出必须检测,两条等价判据:
C_out 与次高位进位 C_in 不同即溢出,V = C_out ⊕ C_in。01/10)即溢出。8 位补码加法溢出示例:
+100 (0110 0100)
+ +50 (0011 0010)
= +150 (1001 0110) ← 符号位变成 1,结果却是 +150 > 127,溢出!
注意:C 的
int溢出是未定义行为(UB),编译器可做任何事;unsigned溢出是明确定义的模 2ⁿ 回绕。别把「补码回绕」当「int 安全溢出」。
实数用科学计数法逼近:(-1)^s × 1.fraction × 2^(exponent - bias)。
| 精度 | 符号 s | 指数 e | 尾数 fraction | bias | 范围量级 |
|---|---|---|---|---|---|
| float | 1 位 | 8 位 | 23 位 | 127 | ~10⁻³⁸ ~ 10³⁸ |
| double | 1 位 | 11 位 | 52 位 | 1023 | ~10⁻³⁰⁸ ~ 10³⁰⁸ |
1,不存,白赚 1 位精度。指数存偏置值(真值+bias),可按无符号整数直接比大小。0.0/-0.0 编码不同但比较相等。0.1 即被舍入成最近近似值。0.1 (double) 的实际存储值 ≈ 0.1000000000000000055511151231257827...
所以 0.1 + 0.2 != 0.3 (结果是 0.30000000000000004)
对比:定点小数位固定,范围小但精度均匀、运算快(纯整数电路,第 3 章);浮点用指数换巨大动态范围,但精度不均匀(数越大间隔越疏,有效位固定 24/53 位)。金融/计时等需精确十进制且无舍入的场景,用定点或十进制库,别用二进制浮点。
C_out ⊕ C_in。浮点加减 = 对阶→尾数运算→规格化→舍入四步,比整数加法慢得多。float/double 对应 IEEE 754,int/unsigned 对应补码。(int)0.1 截断、浮点比较不能用 ==、1/0.0 得 inf、0.0/0.0 得 NaN,根源都在本章。int 溢出是明确定义的补码回绕(非 UB);double 完全遵循 IEEE 754。int 是任意精度大整数(数组存位)不溢出、代价是慢;float 仍是 IEEE 754 double,0.1+0.2 问题照旧。