(实验三)补码的加减法
1. 实验要求
用C/C++编程实现两个十进制整数(将其转换成补码)加、减运算结果,提示思想:模4补码进行计算
2. 相关知识点
机器字长全部假设为 8 位,只讨论整数,后不再特殊说明
0. 符号位
之前我们符号位都是用 1 位表示,模 4 补码是用 2 位表示,对应关系如下:
| 符号位 | 表示 |
|---|---|
| 00 | 正数 |
| 01 | 上溢 |
| 10 | 下溢 |
| 11 | 负数 |
特别提醒:补码运算符号位作为数的一部分参与运算
1. 补码加法
X + Y = [X] 补 _补 补 + [Y] 补 _补 补
- 符号位参与运算
- 如果有多出来的第三个符号位直接丢弃
- 运算结果也是补码
- 最终将运算结果转回真值
2. 补码减法
X - Y = [X] 补 _补 补 + [-Y] 补 _补 补
规则同补码加法
3. 实现思路
0. 准备
包括:
- 检查输入是否合法,即第一个输入为"+“或”-",其后输入为数字
- 确定输入十进制的正负
- 将输入的 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. 效果图



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