常见的编码及其概述:
-
原码(Sign-Magnitude)
- 用最高位(符号位)表示数值的正负,剩余位表示数值的大小。
- 最高位为0:正数;最高位为1:负数。
- 优点:简单直观。
- 缺点:存在“正零”和“负零”。
-
反码(Ones' Complement)
- 正数的表示与原码相同。
- 负数的表示:符号位为1,数值位按原码逐位取反。
- 缺点:同样存在“正零”和“负零”,且计算复杂。
-
补码(Two's Complement)
- 正数的表示与原码相同。
- 负数的表示:符号位为1,数值位为原码的反码+1。
- 优点:计算简单,负数的表示唯一。
- 常用于计算机系统中。
-
移码(Excess-K Code)
- 一种无符号编码。
- 通过对原码整体加一个偏移量 KK(如127、1023)表示数值。
- 常用于浮点数表示中的指数部分。
码之间的转换
-
原码与反码之间的转换:
- 正数:原码和反码相同。
- 负数:反码 = 原码逐位取反(符号位除外)。
-
//正数:原码和反码相同。
//负数:反码 = 原码逐位取反(符号位除外)
int toOnesComplement(int num) {
if (num >= 0) {
return num; // 正数原码和反码相同
}
return ~(-num); // 负数原码转反码
}
int fromOnesComplement(int num) {
if ((num & 0x8000) == 0) {
return num; // 反码为正数时不变
}
return -(~num); // 反码为负数时取反
}
-
原码与补码之间的转换:
- 正数:原码和补码相同。
- 负数:补码 = 原码的反码 + 1。
-
int toTwosComplement(int num) {
if (num >= 0) {
return num; // 正数原码和补码相同
}
return (~(-num) + 1); // 负数原码转补码
}
int fromTwosComplement(int num) {
if ((num & 0x8000) == 0) {
return num; // 补码为正数时不变
}
return -(~(num - 1)); // 补码为负数时转原码
}
-
原码与移码之间的转换:
- 移码 = 原码 + 偏移量 K。
- K通常为
,其中 n为位数 -
int toExcessK(int num, int K) {
return num + K;
}
int fromExcessK(int code, int K) {
return code - K;
}
-
反码与补码之间的转换:
- 正数:反码和补码相同。
- 负数:补码 = 反码 + 1。
-
int onesToTwosComplement(int num) {
if ((num & 0x8000) == 0) {
return num; // 正数反码和补码相同
}
return num + 1; // 负数反码转补码
}
int twosToOnesComplement(int num) {
if ((num & 0x8000) == 0) {
return num; // 正数补码和反码相同
}
return num - 1; // 负数补码转反码
}
完整代码示例
#include <stdio.h>
// 原码 -> 反码
int toOnesComplement(int num) {
if (num >= 0) {
return num; // 正数原码和反码相同
}
return ~(-num); // 负数原码转反码
}
// 反码 -> 原码
int fromOnesComplement(int num) {
if ((num & 0x8000) == 0) {
return num; // 反码为正数时不变
}
return -(~num); // 反码为负数时取反
}
// 原码 -> 补码
int toTwosComplement(int num) {
if (num >= 0) {
return num; // 正数原码和补码相同
}
return (~(-num) + 1); // 负数原码转补码
}
// 补码 -> 原码
int fromTwosComplement(int num) {
if ((num & 0x8000) == 0) {
return num; // 补码为正数时不变
}
return -(~(num - 1)); // 补码为负数时转原码
}
// 原码 -> 移码
int toExcessK(int num, int K) {
return num + K;
}
// 移码 -> 原码
int fromExcessK(int code, int K) {
return code - K;
}
int main() {
int num = -5; // 示例数字
// 原码与反码
int ones = toOnesComplement(num);
printf("原码 -> 反码: %d\n", ones);
printf("反码 -> 原码: %d\n", fromOnesComplement(ones));
// 原码与补码
int twos = toTwosComplement(num);
printf("原码 -> 补码: %d\n", twos);
printf("补码 -> 原码: %d\n", fromTwosComplement(twos));
// 原码与移码 (K = 127)
int excessK = toExcessK(num, 127);
printf("原码 -> 移码: %d\n", excessK);
printf("移码 -> 原码: %d\n", fromExcessK(excessK, 127));
return 0;
}
总结
- 原码直观但有冗余(正零和负零)。
- 反码适合简化取反计算。
- 补码是计算机中最常用的数值表示,解决了原码和反码的问题。
- 移码主要用于特定场景(如浮点数表示)。