当前位置: 首页 > news >正文

什么是原码、反码与补码?

在计算机科学中,数值在内存中的存储和表示是通过不同的编码系统实现的。这些编码系统主要包括原码、反码和补码,它们各自有不同的特点和用途。本指南将详细介绍这些编码系统,帮助您深入理解计算机如何表示和处理数值。

1. 原码(True Form)

原码是最直观的二进制表示方法,直接将数字的绝对值转换为二进制,然后在最高位添加符号位(0表示正数,1表示负数)。

定义与规则

  • 最高位为符号位:0代表正数,1代表负数
  • 其余位表示数值的绝对值

示例

对于8位二进制表示:

+43 的原码:0 0101011 (符号位为0,后面是43的二进制)
-43 的原码:1 0101011 (符号位为1,后面是43的二进制)

特点

  1. 直观性:容易理解和手动转换
  2. 范围:对于n位二进制,范围是 -(2^(n-1)-1) 到 +(2^(n-1)-1)
  3. 缺点:存在两个零(+0和-0),且在算术运算中需要特殊处理

在8位表示中:

  • +0 的原码:0 0000000
  • -0 的原码:1 0000000

原码的局限性

原码在进行算术运算时存在诸多不便:

  • 加法和减法需要比较绝对值大小
  • 需要单独处理符号
  • 存在两个零的表示,浪费了一个编码

2. 反码(One's Complement)

反码是一种改进的编码方式,对于负数,除符号位外,其余位取原码的按位取反(0变1,1变0)。

定义与规则

  • 正数的反码等于其原码
  • 负数的反码是符号位保持不变,其余位按位取反

示例

对于8位二进制表示:

+43 的反码:0 0101011 (与原码相同)
-43 的反码:1 1010100 (符号位为1,其余位取反)

特点

  1. 弥补部分缺陷:使得加减法运算规则更统一
  2. 范围:与原码相同
  3. 依然存在两个零:+0(0 0000000)和-0(1 1111111)

反码的加法

在反码表示中,加法操作得到简化:

  1. 直接按位相加
  2. 如果有进位到符号位之外,则需要将这个进位加回到结果的最低位(称为"端进位循环")

例如:计算 +15 + (-10)

+15 的反码:0 0001111
-10 的反码:1 1110101
按位相加:  1 0000100 (产生进位)
进位回卷:  0 0000101 = +5 (正确结果)

3. 补码(Two's Complement)

补码是现代计算机普遍采用的数值表示方法,它解决了原码和反码的主要缺点。

定义与规则

  • 正数的补码等于其原码
  • 负数的补码等于其反码加1(或者直接从原码取反后加1)

示例

对于8位二进制表示:

+43 的补码:0 0101011 (与原码相同)
-43 的补码:1 1010101 (反码1 1010100加1,或直接原码除符号位外取反后加1)

特点

  1. 统一的零表示:只有一个零(0 0000000)
  2. 简化计算:加减法运算更加自然,无需额外处理
  3. 范围不对称:对于n位二进制,范围是 -2^(n-1) 到 +(2^(n-1)-1) (例如8位补码的范围是 -128 到 +127)

补码的特殊情况

在8位补码表示中,-128(1 0000000)是一个特殊值,它没有对应的正数表示,因为+128超出了8位补码的正数表示范围。

补码的加减法

补码的一个主要优势是简化了算术运算:

  1. 加法:直接按位相加,忽略最高位的进位
  2. 减法:被减数加上减数的补码(等价于加上减数的负数)

例如:计算 +15 + (-10)

+15 的补码:0 0001111
-10 的补码:1 1110110
按位相加:  1 0000101
丢弃进位:  0 0000101 = +5 (正确结果)

4. 移码(Excess Code)

移码是另一种二进制表示法,主要用于表示浮点数的指数部分。

定义与规则

移码是在真值(实际值)的基础上加上一个偏移量(通常是2^(n-1))后得到的编码。

示例

对于8位二进制表示,偏移量为128(2^7):

-43 的移码:128 - 43 = 85 = 0 1010101
+43 的移码:128 + 43 = 171 = 1 0101011

特点

  1. 便于比较大小:移码的二进制表示可以直接比较大小(无需考虑符号)
  2. 广泛用于浮点数指数部分:如IEEE 754标准
  3. 零的表示:通常为偏移量的二进制表示

应用场景

移码最常见的应用是在IEEE 754浮点数标准中表示指数部分:

  • 单精度浮点数使用8位移码,偏移量为127
  • 双精度浮点数使用11位移码,偏移量为1023

5. 各编码系统的比较

下面通过一个表格对比不同编码系统的特点:

特性原码反码补码移码
符号位0为正,1为负0为正,1为负0为正,1为负无显式符号位
负数表示符号位为1,余位为绝对值符号位为1,余位按位取反反码加1真值加偏移量
零的表示+0和-0两种表示+0和-0两种表示唯一表示:全0偏移量的二进制表示
数值范围(8位)-127到+127-127到+127-128到+127-128到+127
加法实现复杂,需要特殊处理需要端进位循环简单,直接按位相加简单,直接按位相加
主要用途较少使用历史上使用整数表示的主流方式浮点数指数部分

6. 在Java中的应用

Java的整数类型(byte、short、int、long)都使用补码表示。以下是一些操作补码的例子:

获取一个数的补码表示

public static void printTwosComplement(int number, int bits) {// 创建一个指定位数的掩码int mask = (1 << bits) - 1;// 应用掩码获取指定位数的补码表示int twosComp = number & mask;// 转换为二进制字符串并补齐前导零String binary = Integer.toBinaryString(twosComp);while (binary.length() < bits) {binary = "0" + binary;}System.out.println(number + " 的 " + bits + " 位补码表示: " + binary);
}

从补码还原为原始值

public static int fromTwosComplement(String binaryStr) {// 检查是否为负数(最高位为1)if (binaryStr.charAt(0) == '1') {// 负数情况:按位取反后加1,再加负号char[] chars = binaryStr.toCharArray();for (int i = 0; i < chars.length; i++) {chars[i] = (chars[i] == '0') ? '1' : '0';}String invertedStr = new String(chars);return -(Integer.parseInt(invertedStr, 2) + 1);} else {// 正数情况:直接转换return Integer.parseInt(binaryStr, 2);}
}

7. 编码转换算法

下面是各种编码之间转换的算法实现:

原码转补码

public static String trueFormToTwosComplement(String trueForm) {if (trueForm.charAt(0) == '0') {// 正数:原码等于补码return trueForm;} else {// 负数:除符号位外按位取反后加1char[] result = trueForm.toCharArray();for (int i = 1; i < result.length; i++) {result[i] = (result[i] == '0') ? '1' : '0';}// 加1操作for (int i = result.length - 1; i > 0; i--) {if (result[i] == '0') {result[i] = '1';break;} else {result[i] = '0';}}return new String(result);}
}

补码转原码

public static String twosComplementToTrueForm(String twosComp) {if (twosComp.charAt(0) == '0') {// 正数:补码等于原码return twosComp;} else {// 负数:除符号位外按位取反后加1char[] result = twosComp.toCharArray();// 减1操作for (int i = result.length - 1; i > 0; i--) {if (result[i] == '1') {result[i] = '0';break;} else {result[i] = '1';}}// 按位取反for (int i = 1; i < result.length; i++) {result[i] = (result[i] == '0') ? '1' : '0';}return new String(result);}
}

8. 实际应用示例

例1:温度传感器数据处理

假设一个8位温度传感器使用补码表示-50°C到+80°C的温度:

public class TemperatureSensor {public static int decodeTemperature(byte rawData) {// 直接将byte解释为有符号数(Java已使用补码)return (int)rawData;}public static byte encodeTemperature(int temperature) {// 检查范围if (temperature < -128 || temperature > 127) {throw new IllegalArgumentException("Temperature out of range");}// 直接转换为byte(Java自动使用补码)return (byte)temperature;}public static void main(String[] args) {// 编码温度byte encoded = encodeTemperature(-15);System.out.println("编码后的二进制: " + String.format("%8s", Integer.toBinaryString(encoded & 0xFF)).replace(' ', '0'));// 解码温度int decoded = decodeTemperature(encoded);System.out.println("解码后的温度: " + decoded + "°C");}
}

例2:计算机网络中的检验和

在网络协议中,常使用一种特殊的补码运算来计算校验和:

public class Checksum {public static short calculateChecksum(byte[] data) {int sum = 0;// 将数据按16位字进行求和for (int i = 0; i < data.length - 1; i += 2) {sum += ((data[i] & 0xFF) << 8) | (data[i + 1] & 0xFF);}// 如果长度为奇数,处理最后一个字节if (data.length % 2 != 0) {sum += (data[data.length - 1] & 0xFF) << 8;}// 将高16位加到低16位while ((sum >> 16) > 0) {sum = (sum & 0xFFFF) + (sum >> 16);}// 取反得到校验和return (short)(~sum);}
}

9. 位操作的优化

在处理二进制编码时,掌握一些位操作技巧可以提高效率:

判断一个数是否为负数(补码表示)

boolean isNegative = (number & (1 << (bits - 1))) != 0;

获取补码表示的绝对值

public static int absoluteValue(int number) {int mask = number >> 31;return (number ^ mask) - mask;
}

不使用if语句计算补码的相反数

public static int negate(int number) {return ~number + 1;
}

10. 总结

理解原码、反码和补码对于深入学习计算机科学和优化算法至关重要:

  1. 原码是最直观的表示方法,但在运算中不方便
  2. 反码改进了部分问题,但仍存在两个零的表示
  3. 补码解决了大多数问题,是现代计算机普遍采用的方案
  4. 移码主要用于浮点数表示和比较

掌握这些编码系统之间的关系和转换方法,有助于理解计算机如何处理数字以及解决相关的编程问题。

在实际应用中,大多数情况下我们不需要直接操作这些编码形式,因为高级编程语言已经封装了相关细节。但在一些特定领域,如嵌入式系统编程、网络协议实现、密码学和底层优化等方面,这些知识仍然非常重要且实用。

相关文章:

  • 2025流感疫苗指南+卫健委诊疗方案|高危人群防护+并发症处理 慢性肾脏病饮食指南2025卫健委版|低盐低磷食谱+中医调理+PDF 网盘下载 pdf下载
  • 牛客1018逆序数-归并排序
  • 金融的本质是智融、融资的实质是融智、投资的关键是投智,颠覆传统金融学的物质资本中心论,构建了以智力资本为核心的新范式
  • PyTorch 张量与自动微分操作
  • 全球化电商平台Azure云架构设计
  • 期末代码Python
  • iptables的基本选项及概念
  • 串 Part 1
  • 数据链路层(MAC 地址)
  • Gemini 解释蓝图节点的提示词
  • STC单片机与淘晶驰串口屏通讯例程之04【密码登录与修改】
  • 有哪些场景不适合使用Java反射机制
  • 基于C++实现的深度学习(cnn/svm)分类器Demo
  • H3C无线控制器自动信道功率调整典型配置实验
  • 数据结构小扫尾——栈
  • JAVA:使用 Maven Assembly 创建自定义打包的技术指南
  • Kubernetes(k8s)学习笔记(七)--KubeSphere 最小化安装
  • 音频感知动画新纪元:Sonic让你的作品更生动
  • 矩阵置零(中等)
  • 五一假期集训【补题】
  • 宋涛就许历农逝世向其家属致唁电
  • 抗战回望18︱《广西学生军》:“广西的政治基础是青年”
  • 特朗普:对所有在国外制作进入美国的电影征收100%关税
  • 抗战回望17︱《青年界》:给一般青年供给一些精神的食料
  • 加拿大总理将赴美同特朗普会晤,重点谈贸易压力
  • “五一”假期首日:国铁南宁局发送旅客81.7万人次