为什么计算机只认识 0 和 1
本讲你将理解:计算机为什么选择了二进制而不是十进制,以及这一选择如何决定了现代计算机的整个架构。
从开关说起
想象你面前有一排电灯开关。
每个开关只有两种状态:开或关。
你不能让一个开关「半开」或「开 37%」——它是二态的,没有中间状态。
计算机内部最基本的元件——晶体管,本质上是和开关一样的东西。
它只有两种稳定状态:导通(通电)和截止(断电)。
电压的两种状态
在数字电路中,我们给这两种状态分别分配一个符号:
- 高电压(比如 3.3V 或 5V)代表 1
- 低电压(接近 0V)代表 0
电压与二进制的关系
下面这条色带模拟了晶体管从 0V 到 3.3V 的电压范围,直观展示逻辑 0、逻辑 1 和禁止区的关系。
逻辑 0 0.5V 1.0V 1.5V
禁止区 1.8V
开始 2.1V 2.7V 3.3V
逻辑 1
逻辑 0 范围:0.0V ~ 1.5V(蓝色区域) | 禁止区:1.5V ~ 1.8V(灰色区域,信号不会停留) | 逻辑 1 范围:1.8V ~ 3.3V(橙色区域)
注意:电路不需要精确测量电压值,只需要判断「高还是低」。
这比判断「是几」要容易得多。
为什么不用十进制
人类使用十进制,因为我们有十根手指。
但为什么计算机不能用十进制呢?
理由一:工程实现极其困难
如果要让电路表示十进制的 10 个数字(0~9),电路需要精确区分 10 个不同的电压等级。
比如:0V = 0,0.33V = 1,0.66V = 2,...,3.3V = 9。
问题来了:信号在传输过程中会有损耗和干扰。
假设你发送了 0.66V 表示数字 2,但到达目的地时电压变成了 0.71V。
接收端就会困惑:这到底是 2(0.66V)还是 3(0.99V)?
理由二:二进制天然抗干扰
二进制只需要区分两种状态,容错空间极大。
如图:逻辑 0 的范围是 0~1.5V,逻辑 1 的范围是 1.8V~3.3V。
中间有 0.3V 的保护区。
即使信号有较大波动,只要不跨过保护区,数据就不会出错。
理由三:与数学完美契合
0 和 1 正好对应布尔代数中的「假」和「真」。
布尔代数(AND、OR、NOT 等逻辑运算)有一套完整的数学理论。
工程师可以用这套理论来设计、分析、优化电路——这是一件非常幸运的事。
计算机选择二进制不是偶然的。它是工程约束(容易实现)、物理特性(抗干扰)和数学工具(布尔代数)三者共同作用的结果。
位和字节——信息的基本单位
一个二进制位称为 1 bit(比特),它只能表示 0 或 1。
显然,单个 bit 能表示的信息太少了。
于是我们把 8 个 bit 组合在一起,称为 1 byte(字节)。
一个字节能表示多少种不同的值?
每个 bit 有 2 种选择(0 或 1),8 个 bit 的组合数是:
2 x 2 x 2 x 2 x 2 x 2 x 2 x 2 = 28 = 256
即从 00000000(十进制 0)到 11111111(十进制 255),共 256 个不同的值。
| 字节数 | 可表示的数值范围 | 常见用途 |
|---|---|---|
| 1 字节 (8 bit) | 0 ~ 255 | 一个 ASCII 字符、RGB 颜色中的一个通道值 |
| 2 字节 (16 bit) | 0 ~ 65,535 | 端口号、早期 CPU 的寄存器大小 |
| 4 字节 (32 bit) | 0 ~ 4,294,967,295 | IPv4 地址、int 类型 |
| 8 字节 (64 bit) | 0 ~ 约 1.8 x 1019 | 现代 CPU 的字长、long 类型 |
交互演示:一个字节的灯泡模拟器
下面这个交互面板让你直观感受 8 个 bit 如何组合出 0 到 255 之间的任意数值。
每个灯泡代表一个 bit。点击灯泡即可切换 0/1 状态,右侧实时显示对应的十进制数值。
灯泡模拟器:一个字节 = 8 位
点击灯泡切换状态,观察二进制如何映射到十进制。
仔细看每个灯泡下方的权重标注。
最左边的灯泡权重最大(128),最右边的权重最小(1)。
这就是「按权展开」的思想——每个位置上的数值乘以它的权重,全部加起来就是最终结果。
用代码理解二进制
Python 内置了对二进制的支持,我们可以直接用它来验证上面的灯泡演示。
实例
# 1. 查看一个数字的二进制表示
print("十进制 → 二进制:")
for n in [0, 1, 2, 7, 8, 15, 16, 42, 65, 97, 127, 255]:
# bin() 返回 '0b...' 格式,用 [2:] 去掉前缀
# zfill(8) 补齐到 8 位
print(f" {n:3d} → {bin(n)[2:].zfill(8)}")
print()
# 2. 从二进制字符串解析为十进制
print("二进制 → 十进制:")
binary_strings = ["00000000", "01000001", "01100001", "11111111"]
for b in binary_strings:
# int(string, 2) 将二进制字符串转为整数
dec = int(b, 2)
print(f" {b} → {dec:3d}")
print()
# 3. 验证:一个字节正好 256 个值
print("一个字节的范围:")
print(f" 最小值: {int('00000000', 2)}")
print(f" 最大值: {int('11111111', 2)}")
print(f" 总个数: {int('11111111', 2) - int('00000000', 2) + 1}")
print()
# 4. 位操作:按位与、或、左移、右移
print("位运算示例:")
a = 0b0011 # 3
b = 0b0101 # 5
print(f" {bin(a)} & {bin(b)} = {bin(a & b)} (按位与)")
print(f" {bin(a)} | {bin(b)} = {bin(a | b)} (按位或)")
print(f" {bin(a)} << 1 = {bin(a << 1)} (左移1位,相当于乘以2)")
print(f" {bin(b)} >> 1 = {bin(b >> 1)} (右移1位,相当于除以2)")
print()
# 5. RUNOOB 测试字符串
text = "RUNOOB"
print(f"字符串 '{text}' 每个字符的二进制表示:")
for ch in text:
ascii_val = ord(ch)
print(f" '{ch}' → ASCII={ascii_val:3d} → 二进制={bin(ascii_val)[2:].zfill(8)}")
为什么二进制是「信息表示」的基础
理解了二进制,你就理解了一个关键事实:
计算机内部的一切——数字、文字、图片、声音、视频——最终都以 0 和 1 的形式存储和处理。
后续几讲中你会看到:
- 第 2 讲:如何在不同进制间转换
- 第 3 讲:负数如何在二进制中表示(补码)
- 第 4 讲:小数如何在二进制中表示(浮点数)
- 第 5 讲:文字如何在二进制中表示(字符编码)
这些内容都建立在「一切皆为 0 和 1」这个基础上。
本模块全部 5 讲的最核心结论:计算机不是「理解」了信息,而是通过精巧的编码规则,把世间万物都映射成了 0 和 1 的组合。
