Python 练习讲解 · 19 / 25

8 位整数:原码、反码与补码

理解计算机如何用固定宽度的二进制位表示正数与负数。

要学习的知识点

题目

补充练习:将 -127 到 127 的整数编码为 8 位原码、反码和补码。

输入一个整数。补充覆盖考试大纲中的数据编码内容。

参考程序:ex19.py;空白练习:lx19.py。

完整代码

以下内容与 ex19.py 一致,可对照右侧讲解阅读。

"""补充练习:将 -127 到 127 的整数编码为 8 位原码、反码和补码。
输入一个整数。补充覆盖考试大纲中的数据编码内容。

学习说明:
- 8 位编码中最高位作为符号位;本练习范围排除了 -128,避免补码范围与原码范围不同的问题。
- 非负数的三种表示相同,直接使用数值即可。
- 负数原码:最高位置 1,其余位保存绝对值。
- 负数反码:对绝对值按位取反,并用 & 0xFF 限制为 8 位。
- 负数补码:相当于 256 加上负数;& 0xFF 取出最低 8 位。
- format(value, "08b") 把数字显示成至少 8 位的二进制字符串。
"""
number = int(input())
if not -127 <= number <= 127:
    raise ValueError("本练习范围为 -127 到 127")

if number >= 0:
    # 正数的符号位为 0,三种编码相同。
    sign_magnitude = number
    ones_complement = number
    twos_complement = number
else:
    # 负数的三种编码按不同规则生成。
    magnitude = -number
    sign_magnitude = (1 << 7) | magnitude
    ones_complement = (~magnitude) & 0xFF
    twos_complement = (-magnitude) & 0xFF

print("sign-magnitude:", format(sign_magnitude, "08b"))
print("ones-complement:", format(ones_complement, "08b"))
print("twos-complement:", format(twos_complement, "08b"))

进阶写法

这版与初学版解决同一道题,使用更精炼的语法或标准库工具。

进阶源码:ex19_adv.py

"""练习 19 进阶版:用位掩码生成 8 位原码、反码和补码。"""
number = int(input())
if not -127 <= number <= 127:
    raise ValueError("本练习范围为 -127 到 127")

magnitude = abs(number)
is_negative = number < 0
sign_magnitude = (int(is_negative) << 7) | magnitude
ones_complement = ((~magnitude) & 0xFF) if is_negative else number
twos_complement = number & 0xFF

print("sign-magnitude:", format(sign_magnitude, "08b"))
print("ones-complement:", format(ones_complement, "08b"))
print("twos-complement:", format(twos_complement, "08b"))

int(is_negative) 把布尔值转成 0 或 1;左移 7 位构造符号位,按位掩码 & 0xFF 保留 8 位。条件表达式选择正数或负数编码规则。

运行结果

示例输入:

-5

程序输出:

sign-magnitude: 10000101
ones-complement: 11111010
twos-complement: 11111011

逐个认识函数

下表根据程序中实际调用的函数和方法整理;自定义函数的实现与算法细节见后续说明。

函数形式功能与返回值注意事项
ValueError(message)内置异常类型,用来表示参数值不符合要求。raise ValueError(...) 会立即抛错并停止当前程序流程。
format(value, format_spec='')返回按格式规范转换后的字符串。格式代码 b 表示二进制,宽度可用于补前导零。
input(prompt='')读取一行文本,返回 str;若提供 prompt 会先显示提示。返回值默认是字符串,计算前通常要做类型转换。
int(value, base=10)把整数文本或数值转换为整数。int('3.5') 不合法;按指定进制解析时可传 base。
print(*objects, sep=' ', end='\n')把对象转换为文本显示;返回 None。默认空格分隔并在末尾换行。

三种表示法

表示正数负数
原码最高位 0 表示正,其他位表示大小。最高位 1 表示负,其他位仍写绝对值。
反码与原码相同。符号位保留为 1,其余数值位取反;本例等价于对 8 位正数取反。
补码与原码相同。正数对应二进制按位取反再加 1;也等价于把负数加 256 后取最低 8 位。

本练习选择 -127 到 127,避开 8 位补码可表示 -128、但原码不能表示其正负对称值的特殊边界。

本题位运算和格式化函数

写法功能与返回值例子 / 注意点
1 << 7整数左移 7 位,结果是二进制的第 8 位权值 128。用于把原码符号位设为 1。
|按位或运算符;任一位为 1,结果该位就是 1。128 | 5 把符号位和绝对值位组合起来。
~value按位取反运算符,不是函数。Python 整数按任意精度表示,负数取反需用掩码限制成 8 位。
& 0xFF按位与掩码;只保留最低 8 位。0xFF 是十六进制的 255,即二进制 11111111。
format(value, "08b")内置格式化函数;返回格式化字符串。b 表示二进制,08 表示宽度 8、不够时左侧补 0。
int(input())读入并转换整数。越界时程序主动抛出 ValueError。

负数 -5 的计算

  1. 原码:符号位 1,绝对值 5 写成 7 位 0000101,合成 10000101。
  2. 反码:对 00000101 的 8 位表示 00000101 取反,得到 11111010。
  3. 补码:在 -5 的二进制结果中只保留低 8 位,得到 11111011;也可由反码加 1。
magnitude = -number       # 5
sign_magnitude = 128 | 5  # 133 -> 10000101
ones_complement = (~5) & 255
twos_complement = (-5) & 255

代码使用 format(..., "08b") 显示位串。提示:原码计算这条示例中的“7 位绝对值”只是说明符号位外的 7 位区域,格式结果统一显示 8 位。

二进制负数的纸笔推导要严格区分“对 8 位正数整体取反”和“符号位保持不变、只反转数值位”的表述。本程序的反码实现是 (~magnitude) & 0xFF。

代码如何运行

  1. 先按左侧题目给出的格式输入数据;程序通过 input() 读取,并在需要时转换数据类型。
  2. 程序自上而下执行语句;遇到条件、循环或函数调用时,按照右侧算法说明更新变量和处理数据。
  3. 最后由 print() 输出计算结果。可将左侧示例输入与输出逐项对照。

先自己跟踪一组小数据,记录循环前后变量的值;这比只看最终答案更容易理解程序。

自己动手试一试

测试 0、正负 1、正负 127;对照纸笔推导的三种 8 位二进制表示。

先在 lx19.py 中独立完成,再运行参考程序比较结果。修改程序时一次只改一个条件或步骤。