Ran Wei/计算机科学系列/02
English
计算机科学基础 — Ran Wei

模块 02: 信息表示

先理解位的含义,再使用它们表示的值:转换进制、解释有符号整数、区分文字与字节,并探究舍入。

约 5 小时4 个时段2 个实验8 道练习6 道自测题

完成后你能够

  • 在十进制、二进制与十六进制间转换整数。
  • 解释指定位宽的范围与溢出。
  • 解释补码位模式。
  • 区分 Unicode 码位与 UTF-8 字节。
  • 有意识地选择精确或近似算术。

开始之前

建议先修模块: 01.

能够跟踪循环。实验会介绍整除 //、取余 % 和库导入;** 表示乘方。

目录

学习计划

5 小时

四个 75 分钟时段,包含练习。拓展任务或不熟悉的先修知识可能需要更多时间。进度本地保存,两种语言共享。

时段 275 分钟
构建与探究
时段 375 分钟
应用与拓展
时段 475 分钟
推理与复习
1

位与位置记数法

位只有 0、1 两种值。八位字节有 256 种模式,含义取决于约定:同一个字节可以是整数、字符的一部分或指令。二进制从右向左的权重为 1、2、4、8 等,因此 1101 表示 8+4+1=13。十六进制权重为 1、16、256,A–F 表示 10–15,每个十六进制数字对应四位。0x2D 即 0010 1101,十进制为 45。

对非负整数反复除以 2,记录余数,再倒序读取即可编码。前导零改变位宽,不改变无符号值。

检查理解

二进制 10110 的十进制值是多少?

完整解答

16+4+2=22。

2

位宽、范围与溢出

w 位有 2^w 种模式。无符号整数范围为 0 到 2^w−1,八位可表示 0–255。255 加一需要九位。固定宽度系统必须规定越界行为:拒绝、回绕、饱和或报错。这些行为不同,不能随意替换。本例转换器拒绝超范围值。

Python 整数按需增长,受内存限制,因此 255+1 本身不会在八位回绕。若要明确模拟八位回绕,可用 (value+1)%256。即使语言整数不固定宽度,存储格式与硬件接口仍可能限制位宽。

检查理解

六位能表示多少个无符号值?

完整解答

64 个:0 到 63。

3

有符号整数与字节序

补码把最高位权重设为 −2^(w−1),其余位保持正权重。八位 11111111 为 −128+127=−1;10000000 为 −128,范围是 −128 到 127,而非 −127 到 127。把位模式先看成无符号 u,最高位为 1 时减去 256。

多字节值还需要字节序。0x1234 的大端存储先放 12 再放 34,小端则先 34 再 12。字节序与有无符号是不同选择,交换数据时要同时规定宽度、符号性和字节序。

检查理解

八位 11111110 的无符号与有符号解释分别是什么?

完整解答

无符号为 254;补码为 254−256=−2。

4

文字编码后才成为字节序列

Unicode 为文字符号分配码位,UTF-8 把码位编码为字节。ASCII 字符占一个 UTF-8 字节,其他许多码位占多个。A中 有两个码位,但占四个 UTF-8 字节。Python str 表示文字,bytes 表示字节序列;进入字节接口时编码,读取时按约定编码解码。

一个可见字符可能由多个码位组成,例如字母加组合重音,因此码位数量不一定等于可见字符数量。任意截断字节可能切开多字节序列,导致解码失败。编码约定是数据格式的一部分。

检查理解

为什么文字长度可能不同于 UTF-8 编码后的字节长度?

完整解答

前者统计码位,后者统计字节,一个码位可能占多个字节。

5

浮点数与精确替代方案

浮点格式保存符号、缩放后的有效数字和指数。有限二进制小数的分母是二的幂。0.1=1/10 的二进制展开重复,有限存储只能舍入。常见 Python 平台上 0.1+0.2 略不同于 0.3,这是表示问题,并非加法任意失效。

近似测量需要按问题选择容差,尤其在零附近结合相对与绝对容差。精确金额可用最小货币单位的整数,或从字符串构造 Decimal。Decimal 也有有限精度上下文,并非每次除法都精确;Fractions 可精确保留有理数,但分子分母可能增长。

检查理解

0.5 与 0.1 能用有限二进制位精确表示吗?

完整解答

0.5=1/2 可以;0.1=1/10 不可以。

交互:解释一个字节

6

常见误解

  • 位模式需要解释规则;未规定有符号格式时,开头的 1 不代表负数。
  • 字节长度、码位数量与可见字符数量不同。
  • 改变显示精度不会改变保存的浮点值。
7

实验准备

下载脚本,在终端中使用 Python 3.11 或更新版本运行:python m02_binary.py. Windows 也可使用 py -3;部分系统使用 python3。实验仅用标准库。先预测结果,再运行并完成变体。不要使用 -O,以保留断言。下方输出由构建器实际运行捕获,两种语言使用相同代码与输出。

8

实验 1 — 构建转换器

跟踪循环中的余数。脚本检查往返转换,并明确拒绝溢出。

下载 m02_binary.py

"""Base conversion and fixed-width signed interpretation."""
def binary(value, width=8):
    if not 0 <= value < 2 ** width:
        raise ValueError("value does not fit unsigned width")
    bits = []
    for _ in range(width):
        bits.append(str(value % 2))
        value //= 2
    return "".join(reversed(bits))

for value in [0, 13, 127, 128, 255]:
    bits = binary(value)
    signed = value if value < 128 else value - 256
    assert int(bits, 2) == value
    print(f"{bits}: unsigned={value:3}, signed={signed:4}, hex={value:02x}")
try:
    binary(256)
except ValueError:
    print("256 rejected at width 8")
else:
    raise AssertionError("overflow must be rejected")
实际运行输出
00000000: unsigned=  0, signed=   0, hex=00
00001101: unsigned= 13, signed=  13, hex=0d
01111111: unsigned=127, signed= 127, hex=7f
10000000: unsigned=128, signed=-128, hex=80
11111111: unsigned=255, signed=  -1, hex=ff
256 rejected at width 8
  1. 预测 42 的输出。
  2. 使用四位,测试 15 和 16。
  3. 解释为何有符号解释在 128 改变。
完整解答

42 是 00101010,十六进制为 2a。四位的 15 是 1111,16 被拒绝。八位符号位权重为 −128,因此无符号 u 至少为 128 时,有符号解释为 u−256。

9

实验 2 — 检查字节与舍入

运行文字往返转换,比较 float 与 Decimal。截断案例明确验证解码错误。

下载 m02_text_float.py

"""Separate text from bytes, and approximate numbers from decimal arithmetic."""
from decimal import Decimal
from math import isclose

text = "A中"
encoded = text.encode("utf-8")
print("code points:", len(text), "bytes:", len(encoded), "hex:", encoded.hex())
assert encoded.decode("utf-8") == text
print("float:", 0.1 + 0.2, "exact equality:", 0.1 + 0.2 == 0.3)
assert isclose(0.1 + 0.2, 0.3, rel_tol=1e-12, abs_tol=1e-12)
exact = Decimal("0.1") + Decimal("0.2")
print("decimal:", exact)
assert exact == Decimal("0.3")
try:
    encoded[:2].decode("utf-8")
except UnicodeDecodeError:
    print("truncated UTF-8 rejected")
实际运行输出
code points: 2 bytes: 4 hex: 41e4b8ad
float: 0.30000000000000004 exact equality: False
decimal: 0.3
truncated UTF-8 rejected
  1. 把文字改为 ASCII 的 ABC。
  2. 尝试把原文字编码为 ASCII。
  3. 比较 Decimal('0.1') 与 Decimal(0.1),解释差异。
完整解答

ABC 有三码位、三个 UTF-8 字节。ASCII 无法编码 中,会抛出 UnicodeEncodeError。从 float 构造 Decimal 保留已舍入的浮点值,从字符串 '0.1' 构造则保留预期十进制输入。

10

练习与完整解答

先尝试,再展开解答。★ 应用概念;★★ 结合概念;★★★ 进行设计或证明。

练习 1 — 转换 45★

把 45 写成八位二进制与十六进制。

完整解答

45=32+8+4+1,所以为 00101101。按四位分组 0010、1101,得到 0x2D。

练习 2 — 无符号范围★

十位无符号范围是多少?

完整解答

2^10=1024 种模式,范围为 0–1023。

练习 3 — 有符号模式★★

用八位补码编码 −5。

完整解答

256−5=251,二进制为 11111011;按 −128+123 解码得到 −5。

练习 4 — 字节序★★

用两种字节序存储两字节的 0x0102。

完整解答

大端为 01 02,小端为 02 01,按各自约定都表示 258。

练习 5 — 截断文字★★

为什么 A中 的前两个字节无法解码?

完整解答

A 占一字节,中 占三字节;截取部分只保留 A 与 中 的第一个字节,UTF-8 序列不完整。

练习 6 — 精确分数★★

1/8 与 1/10 哪个二进制展开有限?

完整解答

1/8 的二进制为 0.001,8 是二的幂;约分后分母 10 含因子五,所以 1/10 重复。

练习 7 — 选择金额表示★★★

设计精确到两位小数且不含分币的价格存储。

完整解答

保存整数分:12.34 保存为 1234,精确求和,在显示边界格式化。还需规定货币、最大金额与税费等运算的舍入规则。

练习 8 — 设计二进制字段★★★

记录包含最大 1000 的无符号计数。规定宽度、符号性与字节序。

完整解答

数学上十位足够。实际字节对齐字段可用两字节无符号大端,仅接受 0–1000。应拒绝保留或超范围值,不能假定每个十六位模式都有效。

11

自测

选择答案查看反馈,重置后可重做。无需 JavaScript 也可阅读答案表。

1

一个字节有多少种模式?

2

八位补码 10000000 是什么?

3

Python int 在 255 后自动回绕吗?

4

UTF-8 编码什么?

5

哪个分数可用有限二进制精确表示?

6

哪种构造保留十进制输入 0.1?

答案表
  1. A — 八位产生 2^8 种模式。
  2. B — 最高位权重为 −128。
  3. C — Python 整数不限制为八位。
  4. A — 文字与字节表示不同。
  5. B — 四是二的幂。
  6. C — 字符串避免中间的二进制近似。
12

引导阅读

13

复习与下一步

编码 29,解释一个八位负数,并说明 A中 为什么需要四个 UTF-8 字节。为目录中的数量与价格选择表示。模块 03 将使用这些值构建程序。

14

关键术语

术语含义
位具有两个可能值的二进制数字。
补码最高位权重为负的有符号解释。
编码值到表示形式的约定映射。
舍入选择接近预期值的可表示值。