计算机系统基础Lab 1 位运算

一、实验内容(实验步骤或者程序编写)

1、安装32位linux虚拟机

2、按照要求补充完bits.c里面的代码

实验前请认真阅读本文档和bits.c中的代码及注释(特别是bits.c前面部分的编程说明与示例),然后根据要求相应完成bits.c中的各目标函数的实现代码。 实验中实现的函数代码必须满足下述基本条件:

只能使用有限类型和数量的C语言算术、逻辑操作,具体要求见每个函数前的注释说明中的"Legal ops"(允许使用的操作符)和"Max ops"(允许使用的最多操作符数量)。

不得使用任何形式的强制类型转换。

不得使用除整型外的任何其它数据类型,如数组、结构、联合等。

不得定义和使用宏。

不得定义除已给定的框架函数外的其他函数,不得调用任何函数。

除上述一般性要求外,非浮点数函数还必须满足下列要求:

只能使用顺序程序结构(即不得使用if、do、while、for、switch等循环或条件分支控制程序结构。

不得使用超过8位表示的常量(即其值必须位于[0,255]中)。

浮点数函数还必须满足下列要求:

可以使用循环和条件控制;

可以使用整型和无符号整型常量及变量(取值不受[0,255]限制);

不得使用任何浮点数据类型、操作及常量。

上述实验要求的主要目的是使得你必须从二进制位的角度考虑数据,进而更清楚地理解数据的二进制表示。

3、安要求检查代码正确性

使用dlc检查函数实现代码是否符合实验要求中的编码规则

完成bits.c后,调用如下命令进行检查:

$ ./dlc bits.c

dlc将返回错误信息如果它发现了错误,例如不允许使用的操作符、过多数量的操作符或者非顺序的代码结构。如果程序代码满足规则要求,dlc将不输出任何提示。 使用-e选项调用dlc

$ ./dlc -e bits.c

可使dlc打印出每个函数使用的操作符数量。 输入" ./dlc -help"可打印出dlc的可用命令行选项列表。

使用btest检查函数实现代码的功能正确性

首先使用如下命令编译生成btest可执行程序:

$ make

如下调用btest命令检查bits.c中所有函数的功能正确性:

$ ./btest

注意每次修改bits.c后都必须使用make命令重新编译生成btest程序。 为方便依次检查测试每一函数的正确性,可如下在命令行使用"-f"选项跟上函数名,以要求btest只测试所指定的函数:

$ ./btest -f bitXor

进一步可如下使用"-1, -2, -3"等选项在函数名后输入特定的函数参数:

$ ./btest -f bitXor -1 7 -2 0xf

(README文件中有关于btest程序的使用说明)

二、实验结果及分析(这部分重点写)

1、作业代码(注释中有每道题的解题思路)

#if 0

#endif

int lsbZero(int x) {
  return (x>>1)<<1; //左移会在低位补零
}

int byteNot(int x, int n) {
  int a = 0xff;
  n<<=3;
  a<<=n;   //取出目标字节
  x^=a;    //取反
  return x;
}

int byteXor(int x, int y, int n) {
  int a = 0xff;
  int b;
  int result;

  n <<= 3;
  x >>= n , y >>= n; 
  x &= a , y &= a;   //取到x和y的第n字节
  b = x^y;      //判断是否相等
  result = !!b;    //映射到0和1
  return result;
}

int logicalAnd(int x, int y) {
  int a;
  x = !!x;   
  y = !!y;    //映射到0和1
  a=x&y;      
  return a;
}

int logicalOr(int x, int y) {
  int a;
  x = !!x;
  y = !!y;     //映射到0和1
  a=x|y;    
  return a;
}

int rotateLeft(int x, int n) {
  int h=x<<n;
  int l=x >> ((n^31)+ 1);  //右移相应位数,其中(n^31)+ 1是求n在mod 32下的补码,相当于32-n;
  l &= ~((~0)<<n);   //高位有可能都是1,将高位变为0
  return l|h;
}

int parityCheck(int x) {
  x ^=(x>>16);          //暴力去做的话,花费肯定会大于20个运算符。用分治的思想,运算次数减少为log(N)
  x ^= (x >> 8);        //一个长为n的数,只考虑 k和k+n/2这两个数中1的个数是不是偶数 (k=1、2、3...n/2),是偶数记为0,由x ^=( x>> (n/2))实现
  x ^= (x >> 4);        //有性质:偶+偶=偶,偶+奇=奇,奇+奇=偶 对应着 0^0=0 0^1=1 1^1=0 ,可以证明算法正确性 
  x ^= (x >> 2);        
  x ^= (x >> 1);        
  x &= 0x1;             // 最后考虑末尾是1还是0即可达到目的。
  return x;
}

int mul2OK(int x) {
  int h1 = (x>>31)&0x1;
  int h2 = ((x<<1)>>31)&0x1;  //取出最高位和次高位
  int ans = (~(h1 ^ h2)) & 0x1; //判断是否相等
  return ans; 
}

int mult3div2(int x) {
  int a=x+x+x;
  int h1=(a>>31)&0x1; //如果是正数,则加0,否则加1
  return (a+h1)>>1;
}

int subOK(int x, int y) {
  int res = x+(~y)+1;         //相当于求出加法器的OF位
  int a = ((res^x)&(x^y))>>31;  //如果两个加数的符号位相同,而与它们的和的符号位不同,则发生溢出
  return !a;
}

int absVal(int x) {
  int a = ((x>>31)&0x1) + ~0;   //如果是正数 a=0xffffffff,如果是负数 a=0x00000000
  x = (~a&(~x+1))|(a&x);        //如果是正数则不做处理,否则取反码加1转化为原码,将符号位变为0
  return x;
}

unsigned float_abs(unsigned uf) {
    unsigned res=uf&0x7fffffff;        //取绝对值
    if(res>0x7F800000){           //判断是否为NaN
        return uf;
    }else{
      return res;
    }
}

int float_f2i(unsigned uf) {
    int fh = (uf>>31)&1;                //取符号位
    int jm = ((uf>>23)&0xff) - 0x7f;    //取阶码,并做预处理(-127),得到解码表示的数字的原码
    int ws = (uf&0x7fffff) | (1<<23);   //取位数,并补上最高位的1

    if(jm<0) return 0;           //绝对值小于,返回0
    if(jm>=31) return 0x80000000u;  //超出int表示范围,返回0x80000000u
    if(jm==0x80) return 0x80000000u; //是NaN或无穷,返回0x80000000u

    if(jm<23){                //处理w尾数
        ws >>= (23-jm);
    }else{
        ws <<= (jm-23);
    }
    
    if(fh){                  //处理符号
      return -ws;
    }else{
      return ws;
    }
}

2、进行语法检查,编译,正确性检查

三、实验心得

最开始做mul2OK这道题的时候,明明代码没有问题,在助教老师的电脑上也能通过,但在我的电脑上就无法通过测试。后来猜测是因为我装的linux系统是64位的原因,于是重新安装了一个32位的linux,问题就解决了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值