(实验三)补码的加减法

1. 实验要求

​ 用C/C++编程实现两个十进制整数(将其转换成补码)加、减运算结果,提示思想:模4补码进行计算

2. 相关知识点

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

0. 符号位

​ 之前我们符号位都是用 1 位表示,模 4 补码是用 2 位表示,对应关系如下:

符号位表示
00正数
01上溢
10下溢
11负数

特别提醒:补码运算符号位作为数的一部分参与运算

1. 补码加法

​ X + Y = [X] 补 _补 + [Y] 补 _补

  1. 符号位参与运算
  2. 如果有多出来的第三个符号位直接丢弃
  3. 运算结果也是补码
  4. 最终将运算结果转回真值

2. 补码减法

​ X - Y = [X] 补 _补 + [-Y] 补 _补

​ 规则同补码加法

3. 实现思路

0. 准备

包括:

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

1. 转二进制

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

2. 转相反数的补码

​ 和转补码类似,转的时候想到它的相反数

3. 实现加法

​ 对于字符串来说,需要先把俩运算的字符串逆序,算出结果了再逆序一次,需要注意的地方就是注意保留进位和进位每次一起运算

3. 补码转真值

​ 生成的结果可能会产生进位,比如 8 位 + 8 位 = 9 位,这种情况下最高位要丢弃,然后判断此时的符号位是 11 10 01 还是 00,10 和 01 的情况是溢出,11 为负,00 为正

​ 但是有特殊情况,比如 [11101010] 补 _补 + [11010110] 补 _补 = [111000000] 补 _补 ,此时应该为溢出,需要在 11 单独处理

4. 具体实现

#include
#include  //abs
#include  //malloc
#include  // reverse
#include   // string
#include  // stringstream
#define PLUS 1    // 正
#define MINUS -1   // 负
#define SYMBOLNUM 2   // 符号位长度
#define WORD_LENGTH 8  // 机器字长
#define MIN (-(1<<(WORD_LENGTH-SYMBOLNUM)))   // 最小取值范围
#define MAX ((1<<(WORD_LENGTH-SYMBOLNUM))-1)  // 最大取值范围
using namespace std;
typedef struct Integer *Number;
struct Integer{        // 定义一个结构体,把该数的各种码放进去string input;  // 输入的带符号十进制整数string binary;  // 二进制真值   Xstring yuan_code;   // 原码string between_bu_code;    // 二进制真值的相反数的补码  [-X]补string bu_code; // 补码   [X]补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(PLUS == num->symbol)   // 如果为正,符号位为 00num->yuan_code += "00";else     // 否则符号位为 1num->yuan_code += "11";//确定原码数值位num->yuan_code += num->binary;  // 原码数值位和二进制相等//补充中间的 0while(num->yuan_code.size() < WORD_LENGTH)   num->yuan_code.insert(SYMBOLNUM,"0");   // 在符号位后面追加 0
}
// 转换补码
void ToBu_code(Number num){if(num->symbol == PLUS){    // 如果是正数,补码 = 原码num->bu_code = num->yuan_code;return;}// 如果输入的是MIN,只有补码能表示if(num->decimal == MIN){num->bu_code += "11";while(num->bu_code.size() < WORD_LENGTH)num->bu_code.insert(1,"0");   // 在符号位后面追加 0return;}//确定数值位bool flag = true;for(int i=num->yuan_code.size()-1;i>=SYMBOLNUM;i--){ //从低到高位if(num->yuan_code[i]=='1'){   if(flag){   // 当第一次遇到 1 时,改变标记值,num->bu_code +="1";flag = false;}elsenum->bu_code +="0";}else{   // 0if(flag)num->bu_code +="0";elsenum->bu_code +="1";}}reverse(num->bu_code.begin(),num->bu_code.end());  // 逆转数组//确定符号位if(num->decimal)   // 只要不是刚好 -0num->bu_code.insert(0,"11");elsenum->bu_code.insert(0,"00");
}
// 转换负的补码
void ToBetweenBu_code(Number num){if(num->symbol == MINUS){    // 如果是负数,负的补码为正num->between_bu_code ="00" + num->yuan_code.substr(SYMBOLNUM);return;}//确定数值位bool flag = true;for(int i=num->yuan_code.size()-1;i>=SYMBOLNUM;i--){ //从低到高位if(num->yuan_code[i]=='1'){   if(flag){   // 当第一次遇到 1 时,改变标记值,num->between_bu_code +="1";flag = false;}elsenum->between_bu_code +="0";}else{   // 0if(flag)num->between_bu_code +="0";elsenum->between_bu_code +="1";}}reverse(num->between_bu_code.begin(),num->between_bu_code.end());  // 逆转数组//确定符号位if(num->decimal)   // 只要不是刚好 -0num->between_bu_code.insert(0,"11");elsenum->between_bu_code.insert(0,"00");
}
// 补码转真值
void bu_code2true_value(string result){// 去掉多余的位数(也许进位产生了 3 位符号位)reverse(result.begin(),result.end());  // 先逆序result = result.substr(0,8);   // 从 0 开始,截取 8 位 reverse(result.begin(),result.end());  // 再逆转回去string true_value;  // 真值// 提取符号位string symbol = result.substr(0,2);// 判断符号位if(symbol=="11"){  // 如果为 11,真值为负bool flag = true;for(int i=result.size()-1;i>=SYMBOLNUM;i--){ //从低到高位if(result[i]=='1'){   if(flag){   // 当第一次遇到 1 时,改变标记值,true_value +="1";flag = false;}elsetrue_value +="0";}else{   // 0if(flag)true_value +="0";elsetrue_value +="1";}}reverse(true_value.begin(),true_value.end());  // 逆转数组// 如果此时真值全为 0,真值又是负,只可能是溢出到 -2^(机器字长-符号位长),根本存不下string tmp="";while(tmp.size() < WORD_LENGTH-SYMBOLNUM)tmp += "0";if(true_value == tmp){cout<<"溢出"<<endl;return;}// 否则其他情况下才可能是个正常负值true_value.insert(0,"-");  // 最前面插入负号}else if(symbol=="10" || symbol=="01"){  // 如果为 01 或者 10,则溢出cout<<"溢出"<<endl;return;}else if(symbol=="00")true_value = "+"+result.substr(2);// 把数值前面多余的0去掉for(int i=1;i<true_value.size();i++)if(true_value[i]=='1'){  // 第一次遇到 1,切到前面的 0 true_value =true_value[0]+true_value.substr(i);break;}cout<<true_value<<endl;
}
// 实现加法,如果 on 为 ture,[x+y]补,否则 [x-y]补
void Add(string x,string y,bool on){string result = "";   // 暂存结果  result = [x]补 + [y]补// 逆序为求和做准备reverse(x.begin(),x.end());reverse(y.begin(),y.end());int flag = 0;   // 记录进位for(int i=0;i<WORD_LENGTH;i++){if(x[i]-'0' + y[i]-'0' + flag >=2){  // 如果和大于等于 2,进位为 1result += (x[i]-'0' + y[i]-'0' + flag)%2 +'0';flag = 1;}else{result  += x[i]-'0' + y[i]-'0' + flag + '0';flag = 0;}}if(flag)result +="1";// 最后结果逆序reverse(x.begin(),x.end());reverse(y.begin(),y.end());reverse(result.begin(),result.end()); cout<<"  "<<x<<"  [x]补"<<endl;cout<<"+ "<<y<<"  "<<(on?"[y]补":"[-y]补")<<endl;cout<<"----------------"<<endl;cout<<" "<<(flag?"":" ")<<result<<"  "<<(on?"[x+y]补":"[x-y]补")<<endl;cout<<"即 x+y =";bu_code2true_value(result);
}
int main(){Number X = new Integer();Number Y = new Integer();cout<<"请输入"<<MIN<<"~+"<<MAX<<"范围内的带符号十进制整数:";cin>>X->input;cout<<"请输入"<<MIN<<"~+"<<MAX<<"范围内的带符号十进制整数:";cin>>Y->input;prepare(X);  // 准备tranfer(X);  // 转换为二进制ToYuan_code(X);    // 转换原码ToBu_code(X);    // 转换补码 [X]补prepare(Y);  // 准备tranfer(Y);  // 转换为二进制ToYuan_code(Y);    // 转换原码ToBu_code(Y);    // 转换补码 [X]补ToBetweenBu_code(Y);   // 转换负的补码  [-X]补 Add(X->bu_code,Y->bu_code,true);   // 实现加法cout<<endl;cout<<endl;cout<<endl;Add(X->bu_code,Y->between_bu_code,false);  // 实现减法free(X);free(Y);return 0;
}

5. 效果图


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部