概述
计算机系统基础实验报告
- 语言 C++
- 编译器 Dev C++
实验一:数的机器级表示
- 编写无符号数的转换:
unsigned int unsignedToValue(char binary[],int n);
要求在main中从屏幕读入n个二进制数即0或者是1,调用unsignedToValue函数返回此二进制数代表的无符号数的真值。 - 编写有符号数的转换:
int intToValue(char binary[],int n);
要求在main中从屏幕读入n个二进制数即0或者是1,调用intToValue函数返回此二进制数代表的有符号数的真值。 - 编写单精度浮点数的转换:
float floatToValue(char binary[]);
要求在main中从屏幕读入32个二进制数即0或者是1,调用intToValue函数返回此二进制数代表的浮点数的真值,要求能够输出非规格化数:无穷大,0,非数。
评分标准:
测试用例占分80分,本次共3+3+5一共11个测试用例,其中带符号数和无符号数6个用例,每个用例正确得10分,浮点数每个测试用例正确得5分,这里注意因为共有5个用例,满分20分,所以这里5个对任意4个就是满分。
带符号整数和无符号整数测试用例:
无符号数:
10000000000000000000000000000000
01111111111111111111111111111111
11111111111111111111111111111111
带符号数:
10000000000000000000000000000000
01111111111111111111111111111111
11111111111111111111111111111111
浮点数测试用例:
11000000111100000000000000000000
10000000000000000000000000000000
01111111111111111111111111111111
01111111100000000000000000000000
00000000011111111111111111111111
代码检查评判标准:
针对测试用例写特例判定代码的,针对一条扣10分
没有实现补码扣40
没有实现浮点数扣40
直接在main函数里实现,此处包括了不按照指导书定义的函数头开发的,本题得0分
代码测试占20分
无符号数,使用pow函数的扣5分,使用乘法运算的扣2分
有符号数,没有调用无符号数函数计算的扣2分,使用pow函数的扣3分,各位取反先计算出真值然后再加1的扣3分
浮点数,没有调用无符号数函数计算指数的扣2分,使用pow函数的扣3分
以上所有函数,在任意函数内调用printf或者cout输出结果的扣5分(这里的意思就是必须在main函数中输出结果,denorms可以除外)
不能判定denorms和非数扣10分
代码严重冗余扣5分(即本次实验的三个函数中任一函数代码行数包含所有子函数超过30行)
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
unsigned int unsignedToValue(char binary[],int n);
int intToValue(char binary[],int n);
float floatToValue(char binary[]);
int main(int argc, char** argv) {
char binary[33];
gets(binary);
// printf("%u",unsignedToValue(binary,32));
// printf("%d",intToValue(binary,32));
printf("%f",floatToValue(binary));
return 0;
}
unsigned int unsignedToValue(char binary[],int n) {
unsigned int sum = 0;
for(int i = 0; i < n; i++) {
sum = sum + ((binary[i]-'0')<<(n-1-i));
}
return sum;
}
int intToValue(char binary[],int n) {
int symbol = 1;
int sum = 0;
if(binary[0]=='1') {
symbol = -1;
for(int i = 31; i > -1; i--) {
if(binary[i]=='1') {
for(int temp = i-1; temp>-1; temp--) {
binary[temp]^=1;
}
break;
}
}
sum = unsignedToValue(binary,32)*symbol;
return sum;
} else {
for(int i = 1; i < n; i++) {
sum = sum + ((binary[i]-'0')<<(31-i));
}
sum = sum * symbol;
return sum;
}
}
float floatToValue(char binary[]) {
float sum = 0;
int exponent = 0;
int symbol = 1;
float significand = 0;
if(binary[0]=='1') {
symbol = -1;
}
for(int i = 1; i < 9; i++) {
exponent = exponent + ((binary[i]-'0')<<(8-i));
}
exponent = exponent - 127;
if(exponent>=0) {
for(int i = 9; i < 32; i++) {
significand = significand + ((binary[i]-'0')<<(exponent))/(float(1<<(i-8)));
}
sum = (significand + (1<<exponent)) * symbol;
} else {
for(int i = 9; i < 32; i++) {
significand = significand + ((binary[i]-'0')/float(1<<(-exponent)))/(float(1<<(i-8)));
}
sum = (significand + (1/float(1<<(-exponent)))) * symbol;
}
if((exponent==128)&&(significand==0)) {
return (1.0/0.0);//Infinity
}
if((exponent==128)&&(significand!=0)) {
return (0.0/0.0);//NaN
}
if((exponent==-127)&&(significand!=0)) {
char denorms[8] = "denorms";
printf("%sn",denorms);
return 0;//Denorms
}
return sum;
}
实验二:定点数加减法的机器级表示
- 编写整数加减法器:
设在main中有如下数组:
char int1[n+1];
char int2[n+1];
编写函数
Char * addsub(char int1[],char int2[],int flag, int n);
当flag为0时表示加法运算,当flag为1时表示减法运算,做n位的加减法运算,将运算结果保存至int2中,在main函数中输出运算结果。m和n分别是int1和int2的长度。在函数中必须要计算OF,CF,SF,ZF,将4个F作为返回值返回,并在main函数中输出4个值,判定是否产生了溢出,是哪一种溢出。
评分标准:
共5个测试用例,测试分数80分。前4个测试用例每个15分,最后一个20分。
0111-0111
0111+1000
0001+1111
0111+0001
0111-1000
代码检查扣分标准:
分别实现加法器和减法器的本题得0分
分别实现无符号加减法和有符号加减法的本题得0分
先分别计算真值,然后做十进制加减法的本题得0分
直接在main函数里实现,此处包括了不按照指导书定义的函数头开发的,本题得0分
针对测试用例写特例判定代码的,针对一条扣20分
代码测试占20分(以下扣分可以重叠,扣到20为止)
在main函数以外的函数中输入输出的扣5分
使用全局变量的扣5分
代码严重冗余扣5分(即addsub函数代码行数包含所有子函数超过50行)
实现全加器时使用if else的扣20分
实现全加器时使用/和%的扣5分
计算OF和CF时使用if else的扣10分
#include <iostream>
#include <stdio.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
char * addsub(char int1[],char int2[],int flag, int n);
int main(int argc, char** argv) {
int n;
cin>>n;
char int1[n+1];
for(int i = 0; i < n+1; i++) {
cin>>int1[i];
}
char int2[n+1];
for(int i = 0; i < n+1; i++) {
cin>>int2[i];
}
char *result;
result = addsub(int1, int2, 1, n);
cout<<"OF:"<<result[0]<<"nCF:"<<result[1]<<"nSF:"<<result[2]<<"nZF:"<<result[3];
printf("n运算结果:");
for(int i = 0; i < (n+1); i++) {
printf("%c",int2[i]);
}
return 0;
}
char * addsub(char int1[],char int2[],int flag, int n) {
char OF = '0', CF = '0', ZF = '0';
int Cin = 0, Cout = 0, Cnsubone = 0;
if(flag==1) { //减法运算,求int2的补码
Cin = 1;
for(int i = n; i >= 0; i--) {
if(int2[i]=='1') {
for(int temp = i-1; temp>-1; temp--) {
int2[temp]^=1;
}
break;
}
}
}
bool carry = false;//判断是否进位
for(int i = n; i >= 0; i--) {
if(!carry) {
if((int1[i]^int2[i])==0) {
if((int1[i]=='1')&&(int2[i]=='1')) {
carry = true;
}
int2[i] = '0';
} else {
int2[i] = '1';
}
} else {
if((int1[i]^int2[i])==0) {
carry = ((int1[i]=='1')&&(int2[i]=='1')) ? true : false;
int2[i] = '1';
} else {
int2[i] = '0';
carry = true;
}
}
if(i==1) {
Cnsubone = carry ? 1 : 0;
}
if(i==0) {
Cout = carry ? 1 : 0;
}
}
int count = 0;
for(int i = 0; i < n+1; i++) {
if(int2[i]=='0') {
count++;
}
}
(count==n+1) ? (ZF='1') : (ZF='0');
char *fourF = new char[4];
((Cout^Cnsubone) == 1) ? (fourF[0] = '1') : (fourF[0] = '0'); //判断OF并且赋值
((Cin^Cout) == 1) ? (fourF[1] = '1') : (fourF[1] = '0'); //判断CF并且赋值
fourF[2] = int2[0];//SF
fourF[3] = ZF;//ZF
return fourF;
}
实验三:同符号浮点数加法运算/无符号定点数乘法运算的机器级表示
- 编写浮点数加法器:
设在main中有如下数组:
char float1[33];
char float2[33];
编写函数
char * addfloat(char float1[],char float2[]);
最终调用实验一floatToValue函数输出浮点数加法的十进制结果,在函数内部要求有保护位和舍入位并通过这两位判定是否舍入。 - 编写n位无符号整数乘法运算器:
char int1[n+1];
char int2[n+1];
编写函数
void mul(char int1[],char int2[],int n);
在运算结束后,将高n位保存在int1中,低n位保存在int2中。
提示: - 乘法运算要求必须编写乘法器,不可以将二进制串先转换为十进制,做乘法运算后再转换为二进制。
- 浮点数加法器应当分为几个函数来写:计算阶码exponent,尾数右移shift,无符号整数加法器add。
- 浮点数加法器的总过程是对阶、尾数相加、右规、舍入
- 注意到尾数共有23位,舍入需要加2位,隐藏的1需要加1位,加法运算有可能进1再加1位,因此尾数用一个27位的数组来表示会大大简化计算难度。
评分标准:
共4个测试用例,测试分数80分。每个20分。浮点数加法注意,只需要实现同符号数加法即可。
乘法:
0011
0011
1000
0010
浮点数:
01000010111100000000000000000000
01000001110100000000000000000000
01111111000000000000000000000000
01111111000000000000000000000000
代码检查扣分标准:
浮点数加法器分别计算真值,然后做十进制加法的本题得0分。
乘法器分别计算真值,然后做十进制乘法的本题得0分
直接在main函数里实现,此处包括了不按照指导书定义的函数头开发的,本题得0分
针对测试用例写特例判定代码的,针对一条扣20分
代码测试占20分(以下扣分可以重叠,扣到20为止)
在main函数以外的函数中输入输出的扣5分(浮点数输出溢出除外)
代码严重冗余扣5分(即浮点数加法器函数,包含所有子函数代码行数超过150行)
代码不判定溢出的扣5分,此处包含了两个函数
浮点数不能返回真值的扣5分
浮点数加法时使用if else的扣10分,使用/和%的扣5分。
不实现舍入扣10分
#include <iostream>
#include <stdio.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
char * addfloat(char float1[],char float2[]);
float floatToValue(char binary[]);
void mul(char int1[],char int2[],int n);
int main(int argc, char** argv) {
//浮点数相加的输入输出
char float1[33];//a
for(int i = 0; i < 32; i++) {
cin>>float1[i];
}
char float2[33];//b
for(int i = 0; i < 32; i++) {
cin>>float2[i];
}
char *result;
result = addfloat(float1,float2);
printf("n二进制结果:");
for(int i = 0; i < 32; i++) {
printf("%c",result[i]);
}
printf("n十进制结果:%f",floatToValue(result));
//乘法器的输入输出
int n;
cin>>n;
char int1[n+1];
for(int i = 0; i < n+1; i++) {
cin>>int1[i];
}
char int2[n+1];
for(int i = 0; i < n+1; i++) {
cin>>int2[i];
}
mul(int1, int2, n);
printf("nint1中保存高n位:");
for(int i = 0; i < n+1; i++){
cout<<int1[i];
}
printf("nint2中保存低n位:");
for(int i = 0; i < n+1; i++){
cout<<int2[i];
}
return 0;
}
char * addfloat(char float1[],char float2[]) {
int protectionBit = 0, roundingBit = 0, exponent1 = 0, exponent2 = 0, shift = 0;//保护位;舍入位; 阶码1;阶码2; 尾数右移位数
char *finalResult = new char[32];
char finalSignificand[23] = {};
for(int i = 1; i < 9; i++) {
exponent1 = exponent1 + ((float1[i]-'0')<<(8-i));
}
for(int i = 1; i < 9; i++) {
exponent2 = exponent2 + ((float2[i]-'0')<<(8-i));
}
shift = (exponent1 >= exponent2) ? (exponent1 - exponent2) : (exponent2 - exponent1);
char significandSmall[23+shift+1] = {};//阶码小的
char significandBig[24] = {};//阶码大的
char significandSum[23+shift+1] = {};
significandSmall[shift] = '1';
significandBig[0] = '1';
for(int i = 0; i < shift; i++) {
significandSmall[i] = '0';
}
if(exponent1 >= exponent2) {
for(int i = 9; i < 32; i++) {
significandSmall[i-9+shift+1] = float2[i];
significandBig[i-8] = float1[i];
}
} else {
for(int i = 9; i < 32; i++) {
significandSmall[i-9+shift+1] = float1[i];
significandBig[i-8] = float2[i];
}
}
for(int i = (23+shift); i > 23; i--) {
significandSum[i] = significandSmall[i];
}
bool carry = false;//判断是否进位
for(int i = 23; i > -1; i--) {
if(!carry) {
if((significandBig[i]^significandSmall[i])==0) {
if((significandBig[i]=='1')&&(significandSmall[i]=='1')) {
carry = true;
}
significandSum[i] = '0';
} else {
significandSum[i] = '1';
}
} else {
if((significandBig[i]^significandSmall[i])==0) {
carry = ((significandBig[i]=='1')&&(significandSmall[i]=='1')) ? true : false;
significandSum[i] = '1';
} else {
significandSum[i] = '0';
carry = true;
}
}
if(exponent1 >= exponent2) {
if((i==0)&&carry) {//右规一次,exponent1(阶码大的)阶码加一
for(int i = 8; i > 0; i--) {
finalResult[i] = float1[i];
}
for(int i = 8; i > 0; i--) {
if(float1[i] == '1') {
finalResult[i] = '0';
} else {
finalResult[i] = '1';
break;
}
}
}
} else {
if((i==0)&&carry) {//右规一次,exponent1(阶码大的)阶码加一
for(int i = 8; i > 0; i--) {
finalResult[i] = float2[i];
}
for(int i = 8; i > 0; i--) {
if(float2[i] == '1') {
finalResult[i] = '0';
} else {
finalResult[i] = '1';
break;
}
}
}
}
}
for(int i = 0; i < 23; i++) {
finalResult[i+9] = significandSum[i];
}
if((float1[0]=='1')&&(float2[0]=='1')) {
finalResult[0] = '1';
} else if((float1[0]=='0')&&(float2[0]=='0')) {
finalResult[0] = '0';
}
//00、01舍;11入;10强制为偶数(若最后一位为1)
if((significandSum[23]=='1')&&(significandSum[24]=='1')) { //11入
if(finalResult[31]=='0') {
finalResult[31] = '1';
} else {
for(int i = 31; i > -1; i--) {
if(finalResult[i]=='1') {
finalResult[i] ='0';
} else {
finalResult[i] ='1';
break;
}
}
}
} else if((significandSum[23]=='1')&&(significandSum[24]=='0')) { //10强制为偶数(若最后一位为1)
if(finalResult[31]=='1') {
finalResult[31] = '0';
for(int i = 30; i > -1; i--) {
if(finalResult[i]=='1') {
finalResult[i] = '0';
} else {
finalResult[i] = '1';
break;
}
}
}
}
return finalResult;
}
float floatToValue(char binary[]) {
float sum = 0;
int exponent = 0;
int symbol = 1;
float significand = 0;
if(binary[0]=='1') {
symbol = -1;
}
for(int i = 1; i < 9; i++) {
exponent = exponent + ((binary[i]-'0')<<(8-i));
}
exponent = exponent - 127;
if(exponent>=0) {
for(int i = 9; i < 32; i++) {
significand = significand + ((binary[i]-'0')<<(exponent))/(float(1<<(i-8)));
}
sum = (significand + (1<<exponent)) * symbol;
} else {
for(int i = 9; i < 32; i++) {
significand = significand + ((binary[i]-'0')/float(1<<(-exponent)))/(float(1<<(i-8)));
}
sum = (significand + (1/float(1<<(-exponent)))) * symbol;
}
if((exponent==128)&&(significand==0)) {
return (1.0/0.0);//Infinity
}
if((exponent==128)&&(significand!=0)) {
return (0.0/0.0);//NaN
}
if((exponent==-127)&&(significand!=0)) {
char denorms[8] = "denorms";
printf("%sn",denorms);
return 0;//Denorms
}
return sum;
}
void mul(char int1[],char int2[],int n) {
//在运算结束后,将高n位保存在int1中,低n位保存在int2中
char *sum = new char[2*(n+1)];
char *temp = new char[2*(n+1)];
for(int i = 0; i < 2*(n+1); i++) {
sum[i] = '0';
temp[i] = '0';
}
for(int i = n; i > -1; i--) {
if(int2[i]=='1') {
for(int k = 0; k < 2*(n+1); k++) {
temp[k] = '0';
}
for(int j = n; j > -1; j--) {
temp[j+i+1] = int1[j];
}
bool carry = false;//判断是否进位
for(int i = (2*n + 1); i > -1; i--) {
if(!carry) {
if((sum[i]^temp[i])==0) {
if((sum[i]=='1')&&(temp[i]=='1')) {
carry = true;
}
sum[i] = '0';
} else {
sum[i] = '1';
}
} else {
if((sum[i]^temp[i])==0) {
carry = ((sum[i]=='1')&&(temp[i]=='1')) ? true : false;
sum[i] = '1';
} else {
sum[i] = '0';
carry = true;
}
}
}
}
}
for(int i = 0; i < (n+1); i++){
int1[i] = sum[i];
}
for(int i = (n+1); i < 2*(n+1); i++){
int2[i-n-1] = sum[i];
}
}
实验四:高级语言的机器级表示
写一段C语言程序包含循环分支和过程调用,查阅并分析汇编代码,下面是参考可写的程序,可以不按照以下程序来写,特别注意可以没有数组。
定义一个数组int sum[5];
通过循环从屏幕输入5个数进数组sum
调用函数int Sum(int sum[])计算数组中所有元素的和并返回
如果返回值大于50则输出平均值大于10,否则输出平均值小于10.
编译通过后查阅汇编代码并结合你写的C语言程序书写报告描述以下问题:
- 函数调用的汇编代码是如何描述的,参数放在什么地址(可以假设%ebp和%esp地址已知)
- 分支语句的汇编描述方法
- 循环的汇编描述方法
提示:
查看汇编代码方法:
编译
设置断点 F11或在Build -> Start Debug ->Step Into
右键点击断点箭头,Go to disassembly
…为了汇编代码简单,C++代码也写得简单
#include <iostream>
#include <stdio.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int Sum(int temp);
int main(int argc, char** argv) {
int temp = 0;
printf("请输入一个数:");
scanf("%d",&temp);
int result = Sum(temp);
printf("n结果数值为:%d",result);
return 0;
}
int Sum(int temp){
for(int i = 0; i < 3; i++){
temp = temp + i;
}
if(temp % 2 == 0){
printf("结果为偶数");
}else{
printf("结果为奇数");
}
if(temp > 10){
printf("n结果大于10");
}else{
printf("n结果小于等于10");
}
return temp;
}
Main:
0x00401552 <+0>: push %ebp
0x00401553 <+1>: mov %esp,%ebp
0x00401555 <+3>: and $0xfffffff0,%esp
0x00401558 <+6>: sub $0x20,%esp//开辟一个大小为20的栈帧
0x0040155b <+9>: call 0x40d5f0 <__main>//调用主函数
=> 0x00401560 <+14>: movl $0x0,0x18(%esp)//把0存进esp寄存器
0x00401568 <+22>: movl $0x48c000,(%esp)//把0赋值给实参temp(int temp = 0)
0x0040156f <+29>: call 0x401529 <printf(char const*, ...)>//调用printf函数输出
0x00401574 <+34>: lea 0x18(%esp),%eax//将实参temp地址放入寄存器eax中
0x00401578 <+38>: mov %eax,0x4(%esp)//将寄存器eax中保存的值赋到第二个参数(&a)中
0x0040157c <+42>: movl $0x48c00f,(%esp)//将字符串%d放到第一个参数中
0x00401583 <+49>: call 0x401500 <scanf(char const*, ...)>//调用scanf输入(scanf("%d",&temp);)
0x00401588 <+54>: mov 0x18(%esp),%eax//将实参temp的值赋到eax寄存器中
0x0040158c <+58>: mov %eax,(%esp)//将eax寄存器中的值赋给temp
0x0040158f <+61>: call 0x4015b3 <Sum(int)>//调用Sum函数(int result = Sum(temp);)
0x00401594 <+66>: mov %eax,0x1c(%esp)//把eax寄存器中的值存到0x1c(%esp)
0x00401598 <+70>: mov 0x1c(%esp),%eax//把0x1c(%esp)处存放的值赋给eax寄存器中
0x0040159c <+74>: mov %eax,0x4(%esp)//把寄存器eax中的值赋给第二个实参result
0x004015a0 <+78>: movl $0x48c012,(%esp)//把字符串存放到第一个参数中
0x004015a7 <+85>: call 0x401529 <printf(char const*, ...)> //调用printf函数输出
0x004015ac <+90>: mov $0x0,%eax//把0存放在eax寄存器中等待返回(根据约定应通过eax返回)
0x004015b1 <+95>: leave
0x004015b2 <+96>: ret//结束,返回0
Sum:
0x004015b3 <+0>: push %ebp
0x004015b4 <+1>: mov %esp,%ebp
0x004015b6 <+3>: sub $0x28,%esp
=> 0x004015b9 <+6>: movl $0x0,-0xc(%ebp)//把0赋给参数i
0x004015c0 <+13>: jmp 0x4015cc <Sum(int)+25>//for循环开始,直接跳转到25
0x004015c2 <+15>: mov -0xc(%ebp),%eax//把参数i存放到eax寄存器中
0x004015c5 <+18>: add %eax,0x8(%ebp)//把寄存器eax中i的值与形参temp相加后赋值给形参temp
0x004015c8 <+21>: addl $0x1,-0xc(%ebp)//i++
0x004015cc <+25>: cmpl $0x2,-0xc(%ebp)//比较参数i和立即数2
0x004015d0 <+29>: jle 0x4015c2 <Sum(int)+15>// 如果i<=2,跳转到15
0x004015d2 <+31>: mov 0x8(%ebp),%eax//把形参temp的值保存在寄存器中
0x004015d5 <+34>: and $0x1,%eax//将寄存器中temp与1做与运算
0x004015d8 <+37>: test %eax,%eax//做按位与操作判断除于2是否等于0
0x004015da <+39>: jne 0x4015ea <Sum(int)+55>//如果不相等,则跳转到55
0x004015dc <+41>: movl $0x48c022,(%esp)//把字符串存放到esp寄存器中
0x004015e3 <+48>: call 0x401529 <printf(char const*, ...)> //调用printf函数输出
0x004015e8 <+53>: jmp 0x4015f6 <Sum(int)+67>//直接跳转到67,分支结束
0x004015ea <+55>: movl $0x48c02d,(%esp) //把字符串存放到esp寄存器中
0x004015f1 <+62>: call 0x401529 <printf(char const*, ...)> //调用printf函数输出
0x004015f6 <+67>: cmpl $0xa,0x8(%ebp)//比较形参temp和立即数10
0x004015fa <+71>: jle 0x40160a <Sum(int)+87>//如果temp<=10,跳转到87
0x004015fc <+73>: movl $0x48c038,(%esp)// 将字符串存放到esp寄存器中
0x00401603 <+80>: call 0x401529 <printf(char const*, ...)> //调用printf函数输出
0x00401608 <+85>: jmp 0x401616 <Sum(int)+99>//跳转到99,分支结束
0x0040160a <+87>: movl $0x48c044,(%esp)//将字符串存放到esp寄存器中
0x00401611 <+94>: call 0x401529 <printf(char const*, ...)> //调用printf函数输出
0x00401616 <+99>: mov 0x8(%ebp),%eax//将形参temp存放到寄存器eax中(根据约定应通过eax返回)
0x00401619 <+102>: leave
0x0040161a <+103>: ret//结束,返回temp
最后
以上就是甜美裙子为你收集整理的计算机系统基础实验报告的全部内容,希望文章能够帮你解决计算机系统基础实验报告所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复