文章目录
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/x-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/x-tex"> ^7 </annotation> </semantics> </math>7-1),即 [0,(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1)];对于负数,最小值是 11111111(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1)),最大值是 10000000(0),即[-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-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/x-tex"> _原 </annotation> </semantics> </math>原 = 00000000,[-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _原 </annotation> </semantics> </math>原 = 10000000
举例:X = +55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _原 </annotation> </semantics> </math>原 = 00110111;X = -55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _原 </annotation> </semantics> </math>原 = 10110111
2. 反码
表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反
规则:最高位是符号位,0 表示正数,1 表示负数,数值部分当 X > 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反 = [X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _原 </annotation> </semantics> </math>原;当 X < 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反 数值位按位取反(不然怎么叫反码,造的就是原码的反!)
范围:原理同原码,对于正数,最小值是 00000000(0),最大值是 01111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1),即 [0,(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1)];对于负数,最小值是 10000000(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1)),最大值是 11111111(0),即[-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1),0],让我们再次聚焦这个 0,反码正负也都有它!
特殊:还不是那个 0 啊~,[+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反 = 00000000,[-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反 = 11111111
举例:X = +55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反 = 00110111;X = -55,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 反 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _反 </annotation> </semantics> </math>反 = 11001000
3. 补码
表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补
规则:最高位是符号位,0 表示正数,1 表示负数,数值部分当 X > 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = [X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _原 </annotation> </semantics> </math>原;当 X < 0,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = [X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 原 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _原 </annotation> </semantics> </math>原 自低位向高位,尾数的第一个 1 及其右边的 0 保持不变,左位的各位取反(或当 X <0 时,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 反码最低位加 1)
范围:对于正数,最小值是 00000000(0),最大值是 01111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1),即 [0,(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-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/x-tex"> ^7 </annotation> </semantics> </math>7-1)),转为补码就是 10000001(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1)),emm那 10000000(-2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7) 难道不是更小吗?那么补码能多存一个???(嗯还真能),再仔细观察前面内容,会发现一件事…[+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = [-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = 00000000,也就是说相比于原码和反码,补码腾出来一个位置…放最小的 10000000,总结起来就是,对于补码,最小值是 10000000(-2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7),最大值是 00000000(0),即[-2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7,0]
特殊:这有俩特殊,一是 0 特殊,[+0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = [-0] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = 00000000,二是补码最小值特殊,能存下 -2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7
举例:X = +7,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = 00000000;X = -128,[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 补 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _补 </annotation> </semantics> </math>补 = 10000000
4. 移码
表示:[X] <math> <semantics> <mrow> <msub> <mi mathvariant="normal"> 移 </mi> </msub> </mrow> <annotation encoding="application/x-tex"> _移 </annotation> </semantics> </math>移
规则:最高位是符号位,1 表示正数,0 表示负数(反了反了!),数值部分同补码
范围:对于正数,移码的最小值是 10000000(0),最大值是 11111111(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1) ,即 [0,2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1];对于负数,移码的最小值是 00000000(-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1)),最大值是 10000000(0),即 [-(2 <math> <semantics> <mrow> <msup> <mn> 7 </mn> </msup> </mrow> <annotation encoding="application/x-tex"> ^7 </annotation> </semantics> </math>7-1),0]
3. 实现思路
0. 准备
包括:
- 检查输入是否合法,即第一个输入为"+“或”-",其后输入为数字
- 确定输入十进制的正负
- 将输入的 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. 效果图