CSAPP Datalab

Datalab实验报告

4月4日


文件再次毁坏做的备份,部分题目进行了思路借鉴

实验准备

  1. 安装Linux虚拟机
  2. 安装gcc编译器,vim编辑器与Archieve Manager
  3. 下载tar文件并用tar xvf datalab-handout.tar解压,获得datalab-handout 文件夹
  4. 用vim命令行操作打开bits.c文件,进行编辑

实验项目、思路分析与成果

整数部分

  1. bitXor
    本题旨在求x,y两个数的位异或。可以采用“取出均为0的位”以及“取出均为1的位”.
    Eg:有x=11010011与y=00110100两个数
    用u=x&y取出x,y均为1的位,用v=(x)&(y)取出x,y均为0的位。
    之后(u)&(v)得出既不全为0也不全为1的位
    代码如下:
    int bitXor(int x, int y) 
    {
        int u=x&y;
        int v=(~x)&(~y);
        return (~u)&(~v);
    }
    
  2. Tmin()
    此题旨在求二进制补码表示的最小数
    显然其为负数,故符号位为1
    而由二进制补码实际值的计算公式:
    val=-( 2 i − 1 2^{i-1} 2i1) a i − 1 a_{i-1} ai1+ 2 i − 2 2^{i-2} 2i2 a i − 2 a_{i-2} ai2+…+2* a 1 a_1 a1+1* a 0 a_0 a0
    可知当 a i − 2 a^{i-2} ai2= a i − 1 a^{i-1} ai1=…= a 1 a_1 a1= a 0 a_0 a0时,值最小
    故可直接用1<<31表示
    int tmin(void) {
        return 1<<31;
    }
    
  3. isTmax
    此题与第二题相反,是在求给出的数是否为二进制补码表示的最大数0111…1111(31个1)
    我们不妨考虑其特殊性质((~(x+1))^x)全为1.可将此作为充分条件考虑。
    但还需要排除特殊情况:二进制补码能表示的最小数也会出现这种情况,故使用(!!(x+1))来排除
    int isTmax(int x){
        v=(~(x+1))^x;
        return (!v)&(!!(x+1));
    }
    
    //本题亦可使用如下代码,但因为不能使用<<,故不使用
    int isTmax(int x) {
        int u=(x<<1)+1;
        int v=~u;
        return (!v)&(!!(x+1));
    }
    
  4. allOddBits(int x)
    最简单的方法是使用!((x&0xAAAAAAAA)^0xAAAAAAAA),但可使用的最大常数是0xAA,故我们开始着手考虑用0xAA进行构造
    考虑到该数有8位,而我们需要32位,故我们采用倍增的方法,以逆向二分对其进行扩展
    int allOddBits(int x) {
        int a_8=0xAA;
        int a_16=(a_8<<8)|a_8;
        int a_32=(a_16<<16)|a_16;
        return !((a_32&x)^a_32);
    }
    
  5. negate
    按二进制补码中一般的表示形式求相反数即可
    int negate(int x) {
        return (~x)+1;
    }
    
  6. isAsciiDigit
    本题为一维求范围相关题目,转换为01相关问题为与端点比大小
    本题中‘-’不允许使用,故将‘-’改为’(~x)+1’
    看相减之后值的最高位,若最高位均为0(均为正数),则满足题意。
    int isAsciiDigit(int x) {
        int u=x+((~0x30)+1);
        int v=0x39+((~x)+1);
        int a=u>>31;
        int b=v>>31;
        return (!a)&(!b);
    }
    
  7. conditional
    可以通过对x进行一系列变换得到u,使x非0时u全为1,x为0时u全为0
    用我们非常常见的(!!x)取反加一,是否越界来化全1或化全0
    int conditional(int x, int y, int z) {
        int u=(~(!!x))+1;
        return (y&u)|(z&(~u));
    }
    
  8. isOrLessEqual
    要分符号一致和符号不一致两种情况讨论,不然会出现越界的情况
    减号不被允许使用,那么在符号不一致时使用取反+1即可
    相减完之后判断最高位符号,其会进行符号整数的扩展
    int isLessOrEqual(int x, int y) {
    int sig_x=(x>>31)&1;
    int sig_y=(y>>31)&1;
    int sit_1=sig_x&(!sig_y);
    int sit_2=(!sig_x)&(!sig_y);
    int sit_3=sig_x&sig_y;
    int v=y+((~x)+1);
    int w=(!(v>>31))&1;
    return sit_1|(sit_2&w)|(sit_3&w);
    }
    
  9. LogicNeg
    分析0和非0数的不同性质:非0数取反加一和原数做或运算,最高位一定为1;
    但0取反加一做或运算为0。
    然后我们便可以右移31位,获得按符号扩展的整数,+1即可获得相应结果。
    int logicalNeg(int x) {
    int u=(~x)+1;
    int v=(u|x)>>31;
    return v+1;		
    }
    
  10. HowManyBits
    因为原码会比补码用的位数少(因为负数补码表示的最高位是1),所以对于用补码表示的负数,转化为正数形式
    然后用二分法判断某一些以2为倍数的数域中是否有1值,若有,则去掉低位只看高位以缩减问题规模,若无,则缩小二分范围,判断能否缩减,直到缩减至问题规模为1
    int howManyBits(int x) {
        int sig=x>>31;
        x=((~sig)&x)|(sig&(~x));
        int a_16=(!!(x>>16))<<4;
        x>>=a_16;
        int a_8=(!!(x>>8))<<3;
        x>>=a_8;
        int a_4=(!!(x>>4))<<2;
        x>>=a_4;
        int a_2=(!!(x>>2))<<1;
        x>>=a_2;
        int a_1=!!(x>>1);
        x>>=a_1;
        return a_16+a_8+a_4+a_2+a_1+x+1;
    }
    

浮点数部分

此时需要把所传入数值分为3个部分:sig(符号位),exp(指数位),frac(有效数字位)

  1. FloatScale2


    本题以无符号整数的二进制形式传入一个浮点数的二进制表示形式
    题目要求将该浮点数的数值乘2
    先将浮点数分几种情况讨论:
    1. NAN:根据题目要求,返回原数
    2. 阶码全为0:frac部分左移1位,模拟真实数据记录情况,并不改变exp的相关特点
    3. 阶码不全为0也不全为1:exp+1(既不是全为0的情况,需要特殊处理;也不会溢出)
    unsigned floatScale2(unsigned uf) 
    {
        unsigned int sig=(uf>>31)&1;
        unsigned int exp=(uf>>23)&(0xFF);
        unsigned int frac=uf&0x7FFFFF;
        if(!(exp^0xFF)) 
            return uf;
        if(!exp) 
            return (sig<<31)+(exp<<23)+(frac<<1);
        return (sig<<31)+((exp+1)<<23)+frac;
    }
    
  2. floatFloat2Int


    本题通俗地说就是手动把浮点型数化为整形。
    我们分几种情况讨论:
    1. 阶码位全为1:根据题目要求,返回0x80000000
    2. 阶码全为0:因为值val=frac* 2 − 126 2^{-126} 2126,整数位必为0,故返回0
    3. 阶码不全为1也不全为0,则先把最高位的1加上,以frac能表示的最高位数:23位为例,分两种情况讨论:
      (1) frca>23:按照浮点数计数方法往左移(exp-23)位
      (2)frac<=23:按照浮点数计数方法,往右移(23-exp)位(只能移动正数位)
    int floatFloat2Int(unsigned uf) {
        int sig=(uf>>31)&1;
        int exp=((uf>>23)&(0xFF))-127;
        int frac=uf&0x7FFFFF;
        if(exp>=31) return 0x80000000;
        if(exp<0) return 0;
        int val;
        frac=frac|(1<<23);
        if(exp>23) 
            val=frac<<(exp-23);
        else
            val=frac>>(23-exp);
        if(sig)
            val=~val+1;
        return val;
    }
    
  3. floatPower2


    先判断x的范围。
    若x>=128,即出现越界的情况,返回+INF,即0x7f800000
    若x<-149,即出现向下溢出至整数位为0的情况(x+127<=-23,向下溢出至无法表示),则返回0
    若-149<=x<-126,即按照浮点数的表示方法,在该数所能表示的frac部分最高位添1
    若-126<=x<128,则按照浮点数的一般表示形式。用x+127得到原来的阶码exp,然后再左移23位
    unsigned floatPower2(int x) {
        int exp=x+127;
        if(x>=128)
            return 0x7f800000;
        if(x<-149)
            return 0;
        if(x>=-126)
            return exp<<23;
        return 1<<(x+149);
    }
    

遇到的问题

  1. 用命令行打开vim编辑器时,即使用:wq,:wq!,:w均有保存,仍然会不定期恢复到初始状态
    原因猜测:命令行中打开的命令存在寄存器(缓存)中,而笔者在电脑上打开了缓存自动清理功能,遂不定期恢复至初始状态。
    解决方法:打开vim编辑器图形界面,点击"save"按钮保存。
  2. 最后一题测评时间过长
    解决方法:笔者也没有解决这个问题,只是把测评程序中的10s改成了30s,然后全部通过
    btest
    测评结果

以上是本次实验报告的全部内容

  • 45
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值