CSAPP datalab解析

结果

在这里插入图片描述

没得满分是因为在isAsciiDigit中使用了>>违规符号。没有用>>感觉不会写……请求各位大佬对此出谋划策,感谢!

写在前面

这部分内容参考Arthals’ ink
btest:用于测试你的函数是否正确。仅在一个小的测试集上进行测试,不能完全保证你的函数是正确的。

# 编译并运行
make && ./btest
# 对某个函数进行单元测试
make && ./btest -f bitXnor
# 对某个函数进行单元测试,且指定测试用例,以 -1 指定第一个参数,依次类推
make && ./btest -f bitXnor -1 7 -2 0xf

dlc:用于检查你的代码是否符合规范。

# 检查是否符合编码规范
./dlc bits.c

driver.pl:用于评分,检查你的函数是否符合规范且正确。

./driver.pl

BitXor

  • int temp = ~(x & y)这一步计算的是 xy 各位同时为1的位置的反,即 temp 中的每个位都代表 xy 对应位不同时为1。换句话说,它标记了 xy 中至少有一个位为0的位置。
  • int a = ~(x & temp)这里使用 x & temp 获取 x 中与 temp 相应位都为1的位。由于 temp 已经标记了 xy 中不同时为1的位置,x & temp 表示 x 是1且 y 是0的位置。~(x & temp) 则将这些位置置为0,其他位置置为1。
  • int b = ~(y & temp)类似于上面的 a,这里计算的是 y 中与 temp 相应位都为1的位,即 y 是1而 x 是0的位置。~(y & temp) 将这些位置置为0,其他位置置为1。
  • return ~(a & b);此步骤中,a & b 会在 xy 中同时为0或同时为1的位上返回1(因为只有这两种情况下,ab 的对应位同时为0,取反后为1)。因此,~(a & b) 将这些位置反转,从而得到 xy 的按位异或结果,即只有当 xy 的某位不同时,该位才为1。
int bitXor(int x, int y) {
        int temp = ~(x&y);
        int a = ~(x&temp);
        int b = ~(y&temp);
  return ~(a&b);
}

allOddBits

本题要求判断奇数位数全为一,其他数返回0。这里采用mask掩码,当x是0xAAAAAAAA时:
1010 1010 1010 1010 1010 1010 1010 1010
|或& 1010 1010 1010 1010 1010 1010 1010 1010
————————————————————————
1010 1010 1010 1010 1010 1010 1010 1010
当x不是0xAAAAAAAA时,以 0x AAF8AAAA为例子:
1010 1010 0111 1000 1010 1010 1010 1010
& 1010 1010 1010 1010 1010 1010 1010 1010
————————————————————————
1010 1010 0010 1000 1010 1010 1010 1010

我们并不在乎偶数位等不等于1还是0 ,&符号是对于奇数位有0的x,这种情况均不符合要求。之后使用^mask ,((x&mask)^mask) 为零的话则说明所有的奇数位为1。

int allOddBits(int x) {
        int  mask0 = 0xAA;
        int mask1 = mask0 << 8;
        int mask2 = mask0 << 16;
        int mask3 = mask0 << 24;
        int mask =  mask0 | mask1 | mask2 | mask3;
        return  !((x&mask)^mask);
        // ((x|mask)^mask)结果为零的话则说明所有的偶数位均为0
}

Tmax

answer1

返回1,如果x是two’s complement number.
two’s complement number 的Tmax是首位为0,其余均为1的数。
Tmax + 1 = Tmin ;
(x+1)^(1<<31) 会把最高位是1 的置为最高位为0的数,最高位是0的会被置为最高位是1的数。
对于1000 0000 0000 0000 0000 0000 0000 1111 + 1 = 1000 0000 0000 0000 0000 0000 0001 0000
1000 0000 0000 0000 0000 0000 0001 0000
^ 0111 1111 1111 1111 1111 1111 1110 1111
————————————————————————
1111 1111 1111 1111 1111 1111 1111 1111
对上数取反的结果就是 0 ,不符合要求。但是-1却能通过 (x+1)^(1<<31) ,故使用((x+1)>>31)排除-1(编码0xFFFFFFFF)。

int isTmax(int x) {
        return !((x+1)^(~x) & ((x+1)>>31)) ;
}

answer2

xTmax (0x7FFFFFFF):x + 1 会变成 Tmin (0x80000000),并且 y ^ (~x) 会是0,!!y 会是1,因此返回1。
x 不是 Tmax: 如果 x 是其他数,y ^ (~x) 会是非零值,或者 y 为0(针对 x = -1 的情况),结果返回0。

int isTmax(int x) {
        //return ( (!((x+1)^(~x))) & ((x+1)>>31) );
        int y = x + 1;
        return !(y ^ (~x)) & !!y;
}

isMax

我有些违规。。

int isTmax(int x) {
        return ( (!((x+1)^(~x))) & ((x+1)>>31) );
        //int isTmax(int x) {
        //int y = x + 1;
        //return !(y ^ (~x)) & !!y;

}

Tmin

int tmin(void) {
  return 1<<31;
}

negate

返回 -x。这个运用书上的结论就好。。

int negate(int x) {
        return ~x+1;
}

isAsciiDigit

0x30 是 0011 0000,0x39是0011 1001。也就是满足第五位和第六位都是1的前提下,第四位如果是零,则剩下三位怎么取都可以。第四位如果是1,剩下的2、3位只能是0,第1位随意。others是用来检测剩下其它位到底是不是1,因为在make && ./btest时,对于-1853013669[0x918d415b]出错了。

int isAsciiDigit(int x) {
        int others = !(x >> 6);
        int x6 = (x & 0x30)>>5;
        int x5 = (x & 0x10)>>4;
        int x4 = (x & 0x08)>>3; 
        int x23 = !(x & 0x06); //x is '~00~', then x23 is 1;it's good.
        return others & x6 & x5 & ((x4 & x23) | !x4);
// 0011 1010
}

conditional

本题要求实现same as x ? y : z . Example: conditional(2,4,5) ,使用!!将数映射到{0,1},如果~x+1的结果全为1的话,使用 &可以保留y的性征,同理z。

int conditional(int x, int y, int z) {
        x = !!x;
        x = ~x+1;
        return (x & y) | (~x & z) ;
}

logicalNeg

只有0与它的补码(它自己)的|的最高位为0。

int logicalNeg(int x) {
        return !((x | (~x+1)) >> 31);
}

Floatscale2

通过按位与操作提取符号位、指数位和尾数位:

  • s:最高位(第31位)为符号位,决定浮点数是正数还是负数。
  • exp:指数位(第23到30位),决定浮点数的数量级。
  • frac:尾数位(第0到22位),决定浮点数的小数部分。
    处理非归一化数(exp == 0 的情况)
  • 如果尾数的最高有效位(第22位)为 1,则此时需要将指数加 1,表示进入归一化数状态,同时将尾数左移一位。否则,直接将尾数左移一位,表示乘以 2。
    处理归一化数(exp != 0exp != 0x7F800000 的情况):
  • 正常情况下,指数加 1,表示乘以 2。如果指数加 1 后变为全 1,则表示结果为无穷大,尾数置为 0。
    最后没想到是要写!(exp ^ 0x7F800000),写成!(~(exp & 0x7F800000 ))不行!?
unsigned floatScale2(unsigned uf) {
        int s = uf & 0x80000000;
        int exp = uf & 0x7F800000;
        int frac = uf & 0x007FFFFF;
        if (exp == 0)
        {
           if (frac & 0x00400000)
           {
                exp += 0x00800000;
                frac = (frac<<1) & 0x007FFFFF;
           }
           else
           {
                frac = frac <<1;
           }
        }
        else if (!(exp ^ 0x7F800000)){
                //  wu qiong
          return uf;
        }
        else {
                exp += 0x00800000;  //如果 `exp == 0x7F800000`,即指数全为 1,表示无穷大或 NaN,直接返回原数值。
                if (exp==0x7F800000){
                        frac = 0;
                }
         return s | exp | frac;       // 最后将符号位、指数位、尾数位重新组合为一个无符号整数返回
}             

floatPower2

unsigned floatPower2(int x)
{
        int exp = x & 0x7F800000;
        int ret;
        exp = exp >> 23;
        if (x>127) return (0xFF<<23);
        if (x<-149) return 0;
        if(x < -126) return 0x1 << (x + 149);
        exp = x + 127;
        ret = exp << 23;
        return ret;

}

howMantBits

最具有难度的一个。
(b16 + b8 + b4 + b2 + b1 + x + 1) 正负数都是因为x -> |x| -1 才要补上1的。

int howManyBits(int x) {
        int s = x>>31;
        int b16,b8,b4,b2,b1;
        x = x ^ s; //calculate right shift 这里无形中是算术右移,s=0xFFFFFFFF
        //result is x -> |x| -1 
        b16 = !!(x>>16) <<4;/* 0000 0000 0000 1000 0000 0000 0000 0000 */
        x = x >> b16;
        b8 = !!(x>>8) << 3;
        x = x >> b8;
        b4 = !!(x >> 4) << 2;
        x = x >> b4;
        b2 = !!(x >> 2) << 1;
        x = x >> b2;
        b1 = !!(x >> 1) << 0;
        x = x >> b1;
        return (b16 + b8 + b4 + b2 + b1 + x + 1);

}
### CSAPP DataLab 武汉大学 `subok` 参数教程 #### 关于 CSAPP DataLab 的背景介绍 CSAPP DataLab 是《计算机系统基础》(Computer Systems: A Programmer's Perspective, CSAPP)教材中的一个重要实验部分,旨在通过一系列基于位运算的操作加深学生对底层硬件和数据表示的理解[^1]。 在完成 DataLab 中的任务后,通常需要将解决方案上传到特定的服务器进行验证。这一过程涉及到了一个名为 `subok` 的参数设置问题。以下是关于如何正确配置以及提交的相关说明: #### 配置与使用 `subok` 参数 当准备向官方或者学校指定平台提交代码时,确保命令行工具能够识别并接受额外选项是非常重要的一步。具体来说,在执行如下形式的提交指令前需确认环境变量已正确定义好: ```bash make submit SUBMITTY_URL="http://your-submission-server/" COURSE_ID="csapp-datalab" USER_ID="wuhan-university-student" ``` 其中涉及到的关键点之一就是——是否允许未优化版本也成功递交?这便是由布尔型标志 `subok` 来决定的事情。如果将其设为 true,则即使某些题目未能达到最优解法的要求也能顺利完成整个流程;反之则会阻止不符合标准的结果被接收[^2]。 因此,在实际操作过程中需要注意以下几点事项来保障顺利通过检验环节: - **检查本地测试结果**:利用自带脚本如 `./btest` 对各个实现逐一校验其功能性和效率指标; ```bash make && ./btest -f functionName [-param value ...] ``` - **调整适当编译器警告级别**:有时候看似无害的小错误可能隐藏着逻辑隐患,故建议启用更严格的检测机制以便及时发现潜在缺陷; - **明确了解评分细则**:不同院校可能会依据实际情况定制化评判准则,务必提前查阅清楚后再着手修改源文件内容直至满足预期目标为止[^3]。 最后附上一段简单示例展示如何构造符合规范要求下的基本框架结构供参考学习之用: ```c /* * Example Function Implementation According To Given Constraints. */ int exampleFunction(int input){ int mask = 0xFFFFFFFF; return ((input >> 1) & mask); } ``` #### 注意事项总结 综上所述,为了保证能够在武汉大学或者其他任何采用相同体系架构的教学场景下高效完成相应练习项目,请牢记上述提到的各项要点,并严格按照指导手册上的提示逐步推进各项工作进程即可达成理想效果[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值