1. 实验要求

​ 设计一个简单的算法,完成从键盘输入一个带符号的十进制整数,求得其原码、反码、补码、移码,机器字长假设 8 位

2. 相关知识点

机器字长全部假设为 8 位,只讨论整数,后不再特殊说明

0. 机器数

​ 计算机中数据通常用二进制数来表示,生活中带+- 号形式表示的数值在计算机技术中称为真值,统一用 X 表示,比如 X = -7、X = +5

​ 但是 + - 号计算机无法识别,于是约定二进制的最高位为符号位,0 表示正号,1 表示负号,这种表示数的形式称为机器数,机器数包含原码、反码、补码和移码。

​ 即 机器数 = 符号位 + 数值部分

1. 原码

表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math>

规则:最高位是符号位,0 表示正数,1 表示负数,数值部分与真值相同

范围:既然 1 位做符号位,剩余 7 位存数值部分,单看数值部分极值要不全为 0,要不全为 1,对于正数,最小值是 00000000(0),最大值是 01111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1),即 [0,(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)];对于负数,最小值是 11111111(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)),最大值是 10000000(0),即[-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1),0],emm这个 0 实在太优秀了,正负都有它,让我们记住它龟儿!

特殊:就是那个突出的 0![+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math> = 00000000,[-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math> = 10000000

举例:X = +55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math> = 00110111;X = -55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math> = 10110111

2. 反码

表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math>

规则:最高位是符号位,0 表示正数,1 表示负数,数值部分当 X > 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math> = [X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math>;当 X < 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math> 数值位按位取反(不然怎么叫反码,造的就是原码的反!)

范围:原理同原码,对于正数,最小值是 00000000(0),最大值是 01111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1),即 [0,(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)];对于负数,最小值是 10000000(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)),最大值是 11111111(0),即[-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1),0],让我们再次聚焦这个 0,反码正负也都有它!

特殊:还不是那个 0 啊~,[+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math> = 00000000,[-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math> = 11111111

举例:X = +55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math> = 00110111;X = -55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _反 </annotation> </semantics> </math> = 11001000

3. 补码

表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math>

规则:最高位是符号位,0 表示正数,1 表示负数,数值部分当 X > 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = [X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math>;当 X < 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = [X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _原 </annotation> </semantics> </math> 自低位向高位,尾数的第一个 1 及其右边的 0 保持不变,左位的各位取反(或当 X <0 时,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> 反码最低位加 1)

范围:对于正数,最小值是 00000000(0),最大值是 01111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1),即 [0,(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)]; 对于负数,补码的最大最小值简直诡异!反码的负数中,最大值是 11111111(0),补码是反码最低位加 1 ,即反码的最大值是…1000000000(9位?),no,只要 8 位所以是 00000000,-0 的最高位符号位竟然是 0 …(是你数值位飘了,还是我符号位提不动刀了?),反码的最小值是 10000000(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)),转为补码就是 10000001(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)),emm那 10000000(-2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7) 难道不是更小吗?那么补码能多存一个???(嗯还真能),再仔细观察前面内容,会发现一件事…[+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = [-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = 00000000,也就是说相比于原码和反码,补码腾出来一个位置…放最小的 10000000,总结起来就是,对于补码,最小值是 10000000(-2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7),最大值是 00000000(0),即[-2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7,0]

特殊:这有俩特殊,一是 0 特殊,[+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = [-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = 00000000,二是补码最小值特殊,能存下 -2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7

举例:X = +7,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = 00000000;X = -128,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _补 </annotation> </semantics> </math> = 10000000

4. 移码

表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 移 </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> _移 </annotation> </semantics> </math>

规则:最高位是符号位,1 表示正数,0 表示负数(反了反了!),数值部分同补码

范围:对于正数,移码的最小值是 10000000(0),最大值是 11111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1) ,即 [0,2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1];对于负数,移码的最小值是 00000000(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1)),最大值是 10000000(0),即 [-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application&#47;x&#45;tex"> ^7 </annotation> </semantics> </math>7-1),0]

3. 实现思路

0. 准备

包括:

  1. 检查输入是否合法,即第一个输入为"+“或”-",其后输入为数字
  2. 确定输入十进制的正负
  3. 将输入的 string 转换为 int 类型

1. 转二进制

​ 由准备工作准备好的 int 类型的数字直接转换为二进制,不过要注意两点,一是当数字为 0 时,取不到值,这时我们自己手动添个 0 上去,二是当数字为负数时,结果就很迷…解决方法是用其他变量来取数字的绝对值

2. 实现原码

​ 原码比二进制多了符号位,另外还要补够机器字长数,补 0

3. 实现反码

​ 当输入的数为正时,直接等于原码就 ok,当输入为负,反码就是原码数值位取反

4. 实现补码

​ 当输入的数为正时,直接等于原码就 ok,当输入为负时,补码如果是实现反码最低位加一稍微有点麻烦,还要考虑特殊情况。所以用的是最低位向高位扫描,当遇到第一个 1 开始取反

5. 实现移码

​ 移码数值位和补码相等

4. 具体实现

#include<iostream>
#include<cmath> //abs
#include<malloc.h> //malloc
#include<algorithm> // reverse
#include<string> // string
#include<sstream> // stringstream
#define PLUS 1 // 正
#define MINUS -1 // 负
#define WORD_LENGTH 8 // 机器字长
#define MIN (-(1<<(WORD_LENGTH-1))) // 最小取值范围
#define MAX ((1<<(WORD_LENGTH-1))-1) // 最大取值范围
using namespace std;
typedef struct Integer *Number;
struct Integer{        // 定义一个结构体,把该数的各种码放进去
	string input;  // 输入的带符号十进制整数
	string binary;  // 二进制真值
	string yuan_code;   // 原码
	string fan_code;  // 反码
	string bu_code; // 补码
	string yi_code;    // 移码
	int symbol;  // 符号位
	int decimal; // 十进制整数
};
/* 准备工作 1.检查输入是否合法 2.确定输入十进制数的正负 3.将 string 类型转换成 int 类型 4.确定输入十进制数的范围 */
void prepare(Number num){
	// 验证输入合法性,确定该十进制整数的正负
	for(int i=0;i<(num->input.size());i++){
		if(num->input[0]=='+' && !i){    // 如果第一个字符为 +
			num->symbol = PLUS;    // 记录符号为 +
		}else if(num->input[0]=='-' && !i){  //如果第一个字符为 -
			num->symbol = MINUS;   // 记录符号为 -
		}else if(!((num->input[i]>='0' || num->input[i]<='9') && i)){  // 如果不是第一个字符,且不在 0~9 之间
			cout<<"输入不合法,请重新启动!\n"<<endl;    
			exit(0);            // 提示并结束程序
		}
	}
	// 转换输入十进制整数的类型
	stringstream container;   // 转换容器
	container<<num->input.substr(1);      // "吞"进输入的十进制整数 
	container>>num->decimal;      // 再将容器中的数"吐"出来
	num->decimal *= num->symbol;  // 带上符号
	
	//确定输入十进制数的范围
	if(num->decimal < MIN || MAX < num->decimal){  // 如果取值比最小值还小,或者比最大值还大,说明超出表示范围了
		cout<<"超出表示范围,请重新启动!\n"<<endl;
		exit(0);     // 提示并结束程序
	}
}
// 转二进制
void tranfer(Number num){
	int tmpDecimal = abs(num->decimal); 
	// 特殊情况 0 
	// 如果 decimal 为 0,初始化字符串为 0,否则初始化为空
	num->binary=(tmpDecimal==0?"0":""); 
	while(tmpDecimal){
		num->binary += tmpDecimal%2+'0';
		tmpDecimal /=2;
	}
	reverse(num->binary.begin(),num->binary.end());  // 逆转字符串
}
// 转换成原码
void ToYuan_code(Number num){
	// 如果输入的是MIN,只有补码能表示,原码置为 ——
	if(num->decimal == MIN){
		num->yuan_code = "——";
		return;
	}
	// 确定原码符号位
	if(0 < num->symbol)   // 如果小于 0,符号位为 1
		num->yuan_code += "0";
	else     // 否则大于 0 ,符号位为 0
		num->yuan_code += "1";
	//确定原码数值位
	num->yuan_code += num->binary;  // 原码数值位和二进制相等
	//补充中间的 0
	while(num->yuan_code.size() < WORD_LENGTH)   
		num->yuan_code.insert(1,"0");   // 在符号位后面追加 0
}
// 转换反码
void ToFan_code(Number num){
	if(num->symbol > 0 ){  // 如果是正数,反码 = 原码
		num->fan_code = num->yuan_code;
		return;
	}
	// 如果输入的是MIN,只有补码能表示,反码置为 ——
	if(num->decimal == MIN){
		num->fan_code = "——";
		return;
	}
	// 符号位
	num->fan_code += "1";
	//确定反码数值位
	for(int i=0;i<num->binary.size();i++){
		if(num->binary[i]=='0')
			num->fan_code += "1";
		else
			num->fan_code += "0";
	}
	//补充中间的 1
	while(num->fan_code.size() < WORD_LENGTH)   
		num->fan_code.insert(1,"1");   // 在符号位后面追加 1
}

// 转换补码
void ToBu_code(Number num){
	if(num->symbol > 0){    // 如果是正数,补码 = 原码
		num->bu_code = num->yuan_code;
		return;
	}

	// 如果输入的是MIN,只有补码能表示
	if(num->decimal == MIN){
		num->bu_code += "1";
		while(num->bu_code.size() < WORD_LENGTH)
			num->bu_code.insert(1,"0");   // 在符号位后面追加 0
		return;
	}
	//确定数值位
	bool flag = true;
	for(int i=num->yuan_code.size()-1;i>0;i--){ //从低到高位
		if(num->yuan_code[i]=='1'){   
			if(flag){   // 当第一次遇到 1 时,改变标记值,
				num->bu_code +="1";
				flag = false;
			}
			else
				num->bu_code +="0";
		}else{   // 0
			if(flag)
				num->bu_code +="0";
			else
				num->bu_code +="1";
		}
	}
	reverse(num->bu_code.begin(),num->bu_code.end());  // 逆转数组
	//确定符号位
	if(num->decimal)
		num->bu_code.insert(0,"1");
	else
		num->bu_code.insert(0,"0");
}
// 转移码
void toYi_code(Number num){
	// 取得补码的全部位
	num->yi_code = num->bu_code;
	// 替换符号位
	if(num->bu_code[0] =='0') 
		num->yi_code.replace(0,1,"1");
	else
		num->yi_code.replace(0,1,"0");
}
int main(){
	Number num = new Integer();
	cout<<"请输入"<<MIN<<"~+"<<MAX<<"范围内的带符号十进制整数:";
	cin>>num->input;
	prepare(num);  // 准备
	tranfer(num);  // 转换为二进制
	ToYuan_code(num);    // 转换成原码
	ToFan_code(num);   // 转换成反码
	ToBu_code(num);    // 转换成补码
	toYi_code(num);  // 转换移码
	cout<<"输入:"<<num->input<<endl;
	cout<<"原码:"<<num->yuan_code<<endl;
	cout<<"反码:"<<num->fan_code<<endl;
	cout<<"补码:"<<num->bu_code<<endl;
	cout<<"移码:"<<num->yi_code<<endl;
	free(num);
	return 0;
}

5. 效果图