深入理解计算机系统系列03初步探索实验的奥秘

深入理解计算机系统系列03初步探索实验的奥秘
本文借以cmu的实验,详细写了该实验(datalab)的具体思路,借鉴了多篇博客的总结,并在一些题目中给出了多解,并且由于cmu的实验变动,虽然老师一直在讲不周山的博客,但是不周山做的题是好久以前的,又很久没有更新,我又整合了一些原理的cmu的实验题,作为补充题目,具体在注释中都已经写到。(排版可能比较丑,勿怪,还需多多练习)
话不多说,直接上手实验
/下面是题面,我删去了前面一些说明,大概意思是说一下 用法和要求(比如要求是直线型的代码,,大概不能使用循环和条件语句吧)/
/并且通过网络整理的各个版本的题目,包括现在的题目,和不周山的博客上的题目,本人只是整理了关于前面大半部分的
整数部分的题目,对浮点数的题目只上了题面,有时间会继续写
/
//注意将文件放到linux环境下
在Linux下测试以上函数是否正确,指令如下:
*编译:./dlc bits.c
测试:make btest
./btest
//1
/

  • bitXor - x^y using only ~ and &
  • Example: bitXor(4, 5) = 1
  • Legal ops: ~ &
  • Max ops: 14
  • Rating: 1
    */
int bitXor(int x, int y) {
  return  ~(~(~x&y)&~(x&~y));;//受到离散数学的一个定律的启发
}

/*

  • tmin - return minimum two’s complement integer //大概意思是返回补码表示的最小数吧
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 4
  • Rating: 1
    *///这个数字应该是0x8000 0000
int tmin(void) {

  return 1<<31;

}

//2
/*

  • isTmax - returns 1 if x is the maximum, two’s complement number,and 0 otherwise
  • Legal ops: ! ~ & ^ | +
  • Max ops: 10
  • Rating: 1
    */
    //这个题一星难度无法理解了,可能是我太菜了,这题想了很久,还结合了别人的写的
    //思路:最大值为0x7fff ffff,加一会变为0x10000000
    //而此数加上本身后会变为0,本身加本身为0的数只有0和0x1000 0000,故而再将0xffffffff排除即可
    //这里出现了一个问题,如何排除,所以我们重新提一下关于!和的区别,!是逻辑取反,大概意思是0和非0,而是按位取反
    //所以排除用&给出0x7fff ffff二者都具有的情况而0xffffffff不具备后者的情况
int isTmax(int x) {
 return (!(x+1+x+1))&(!!(x+1));//这里我们注意第二部分,!!并不是毫无道理的,事实上,第一个!将数字转化为逻辑值,之后第二个!就是排除了
}
//总结坑:1.!和~的区别2.排除3.两个!!4.本身加本身确实比较难想,不知道别人是怎么想到的

/*

  • allOddBits - return 1 if all odd-numbered bits in word set to 1 //大致意思是基数位都设为1时返回1
  • where bits are numbered from 0 (least significant) to 31 (most significant)
  • Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 12
  • Rating: 2
    */
//这里注意一下,从例子可以看出,这里的奇数和偶数是从0算起的
 //然后此时发现这个时候数字的位置是确定的,之后我们按位取反,得到的数也是固定的,思路就此出现,x与一个固定的数&之后为零,再!
 //把那个固定的数求出来
int allOddBits(int x) {
  unsigned inta=85;

  unsigned intb=a+(a<<8)+(a<<16)+(a<<24);

  return !(b&x);
}

/*

  • negate - return -x
  • Example: negate(1) = -1.
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 5
  • Rating: 2
    */
    //这道题反而两颗星,难以理解,课上的重点知识点
int negate(int x) {
  return ~x+1;
}

//3
/*

  • isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters ‘0’ to ‘9’)
  • Example: isAsciiDigit(0x35) = 1.
  • isAsciiDigit(0x3a) = 0.
  • isAsciiDigit(0x05) = 0.
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 15
  • Rating: 3
    */
//这道题的初始想法是从反面来求,后来写出来发现直接析取出几位就行了
int isAsciiDigit(int x) {
  return (!((x>>3)&0x7)^(0x7))&(!(x>>6))//这题答案应该是不固定的,我没有使用+号
}//这里我们得到了判断一个数是否等于一个常数的方法,看^之后是否为0
//下附加从一个博客中看到的方法 return(!((x+~48+1)>>31))&!!((x+~58+1)>>31);具体思路是将x与临界点作差,然后右移之后观察符号位

/*

  • conditional - same as x ? y : z
  • Example: conditional(2,4,5) = 4
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 16
  • Rating: 3
    */
//条件运算符的实现方法,首先想法是通过判断x是否非零,然后去向两个通路,两个通路如何表示那,想了想,觉得可以通过y和z都进行某种操作
//的或来表示,注意这里y与z的操作应该是相反的
int conditional(int x, int y, int z) {
  return  ((!x+~1+1)&y)|((~!x+1)&z)
}//这里结合一下网上一个博客思路,大体的部分已经想出来了,主要是需要两个部分,分别掌握在x为0和非0的时候的值,这个做法是先将
//x转化为!x的这个时候我们就有两种情况了,0和1,我们析取的时候需要-1,化为0的时候需要零,但是最后一步好像可以不用这么麻烦
//都减去1就可以了,即return ((!x+~1+1)&y)|((!!x+~1+1)&z)

/*

  • isLessOrEqual - if x <= y then return 1, else return 0
  • Example: isLessOrEqual(4,5) = 1.
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 24
  • Rating: 3
    /
    //一开始想从反面看,直接看x-y的符号位,好像就可以
    //但是后来想了想,好像会有溢出的情况哎
    //于是看了下网上的思路,果然要复杂很多
    /

    1.在x与y同号的情况下转换为p=y-x>=0,然后p符号位(p>>31)&1为0则返回1,符号位1则返回0;

2.异号时,只要x>=0,就要返回0,否则返回1,由(x>>31)&1能达到该效果;

3.c=a+b可作为x,y同号异号的判断。
*/
//而后开始具体实现上的东西,其实是差不多的,但是多了一个溢出部分的处理

int isLessOrEqual(int x, int y) {
  int a=x>>31;

  int b=y>>31;

  int c=a+b;//有三种情况,0,1,2但是其实是两种情况,1和非1,1代表异号,非1代表同号

  int p=y+(~x+1);//p=y-x

  int q=!((p>>31)&1);//q=p符号位的非

  int r=(c&(a&1))|((~c)&q);//这里有一个点,如何判断同号和异号怎么做成分枝
  //注意,因为这里是只判断一个位的,所以c=0和2是没有区别的

  return r;  
}
//总结:这道题确实比较难了,有一些过程比较难想,主要考察了关于溢出的一些理解

//4
/*

  • logicalNeg - implement the ! operator, using all of
  • the legal operators except !
  • Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
  • Legal ops: ~ & ^ | + << >>
  • Max ops: 12
  • Rating: 4
    */
    //此时我们有两种情况,0和非0,如何判定为0那
    //有一种想法,应该会用到x+~x,但是还不知道怎么用
    //之后还是参考了别人的代码,构造了y=~x+1,这个是真的不好想,十分巧妙
    /*A.当x为0时,两者符号位都为0;

B.当x=0x8000 0000时,两者符号位都为1;

C.否则,两者符号位为01或10;

D.根据离散数学的真值表得出(x)&(y).*/

int logicalNeg(int x) {
  return((~(~x+1)&~x)>>31)&1;//注意一点,最后是必须要&1的,因为前面可能是有负数的,算数右移,会出现一堆1
  //总结:这个题目真心不太好想,并且最后还有一个坑,算数右移
}

/* howManyBits - return the minimum number of bits required to represent x in two’s complement

  • Examples: howManyBits(12) = 5
  • howManyBits(298) = 10
  • howManyBits(-5) = 4
  • howManyBits(0) = 1
  • howManyBits(-1) = 1
  • howManyBits(0x80000000) = 32
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 90
  • Rating: 4
    */
    //注意这个题目的意思大概是最少位置上考虑左边数第一个为符号位
    /*思路:二分法,举例x=0000 1000 1001 0000 0000 0000 0000 0000说明:

A.令y=x>>16=0000 1000 1001 0000,shift16=(!!y)<<4使用(!!y)如果y为0,则返回0,说明前16位都为0,shift16=0,否则!!y=1,shift16=16,使x=x>>shift16=10001001 0000;
B.同理,令y=x>>8=0000 1000,shift8=(!!y)<<3使用(!!y)如果y为0,则返回0,说明前8位都为0,shift8=0,否则!!y=1,shift8=8,使x=x>>shift8=00001000;
C.令y=x>>4=0000,shift4=(!!y)<<2使用(!!y)如果y为0,则返回0,说明前4位都为0,shift4=0,否则!!y=1,shift4=4,使x=x>>shift4=00001000;
D.令y=x>>2=0000 10,shift2=(!!y)<<1使用(!!y),如果y为0,则返回0,说明前2位(原始的x[27]x[26])都为0,shift2=0,否则!!y=1,shift2=2,使x=x>>shift2=000010;
E.令y=x>>1=0000 1,shift1=(!!y),使用(!!y)如果y为0,则返回0,说明前1位都为0,shift1=0,否则!!y=1,shift1=1,使x=x>>shift1=00001;
F.然后令sum=2+shift16+shift8+shift4+shift2+shift1即可;
G.对于负数取反码即可,对于-1和0特殊考虑。*/
//想了一段时间,放弃了,直接看了一下别人的思路
//这个题的这个解的方法,居然用到了算法方面的二分思想,而且他写的有点复杂,大概意思就是,将x不断二分
//这里他的写法有点简陋,具体是这样的,以一开始的16位右移为例,先根据他的写法判断,前16位是否为零,
//若前16位为零,那就要开始判断后16位置了,这个时候我们的x的更新其实是不变的,这时x=x>>shift16等价于x=x
//而若前16位不为零,那就要开始判断前8位了,这个时候我们的x的更新其实是要更新的x=x>>shift16,等价于x=x>>16
//我们在这个时间段储存了前面的结果,并且进行了分枝,写法十分漂亮
//而之后,我们注意一下sum的值,这个时候我们的sum会差2,这个2是凑出来的(至少我是这么认为的哈)
//还有,负数取反码的问题,因为我们并不在意我们所需要的值的结果,那么这个时候,我们在不考虑符号位的情况下,
//我们将前面的多个1都取得反码来说就行了,这个时候我们的负数取反码可以简化计算
//最后,(这个题是真的不好弄),进行了将二进制的全0和全1的情况进行考虑,他的处理方法还有点可以研究的地方
/我们给出一个t和t2(t和t2的具体含义见代码注释),当t2为1时,即此时x为-1时,会返回1,而当t2=0时候,
我们下面做一个定义,当x=0时候,t2=0并且t=-1(二进制),而当x=-1时,t2=1,并且t=1,所以用|符号连接,两边由上面的
题目的结论,我们采用将|符号两边的操作相反的操作
/

int howManyBits(int x) {

 int shift1,shift2,shift4,shift8,shift16;

 int sum;

 int t=((!x)<<31)>>31;//x为0时,t(二进制)全为1,x不为0时,全为1

 int t2=((!~x)<<31)>>31;//当x为-1时,t2全为1,否则,全为0

 int op=x^((x>>31));//正数不变,负数取反
//注意一下,取反码的方式
 shift16=(!!(op>>16))<<4;//如果高十六位全为0,则0左移4位,不全为0,则1左移4(表示op要右移2^4位)位

 op=op>>shift16;

 shift8=(!!(op>>8))<<3;

 op=op>>shift8;

 shift4=(!!(op>>4))<<2;

 op=op>>shift4;

 shift2=(!!(op>>2))<<1;

 op=op>>shift2;

 shift1=(!!(op>>1));

 op=op>>shift1;

 sum=2+shift16+shift8+shift4+shift2+shift1;

 return (t2&1)|((~t2)&((t&1)|((~t)&sum)));

}

/注意,该题为补充题目,属于原来cmu的实验,而且比较难,不过,印象中南京大学的那个网课好像讲了相关的内容,
而且网课的老师没有细讲,我还查阅了一些资料,最后才仔细看了看代码,才最后明白道理
/
//题面的大概意思是返回二进制1的个数,因为Max ops的限制,肯定是不能一位一位地右移的
//大概思路是,将每个字节的1的个数算出来,然后通过二分的思想,转换到一个字节上,最后求出结果,
//这个思想很有趣,当时还在看网课的时候惊叹,这次补充就顺便直接补充到博客上了
/*

  • bitCount - returns count of number of 1’s in word
  • Examples: bitCount(5) = 2, bitCount(7) = 3
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 40
  • Rating: 4

*/

int bitCount(int x) {
        int result;
        //int mask1=(0x55)|(0x55<<8)|(0x55<<16)|(0x55<<24);
        int tmp_mask1=(0x55)|(0x55<<8);
        int mask1=(tmp_mask1)|(tmp_mask1<<16);
        //int mask2=(0x33)|(0x33<<8)|(0x33<<16)|(0x33<<24);
        int tmp_mask2=(0x33)|(0x33<<8);
        int mask2=(tmp_mask2)|(tmp_mask2<<16);
        //int mask3=(0x0f)|(0x0f<<8)|(0x0f<<16)|(0x0f<<24);
        int tmp_mask3=(0x0f)|(0x0f<<8);
        int mask3=(tmp_mask3)|(tmp_mask3<<16);
        int mask4=(0xff)|(0xff<<16);
        int mask5=(0xff)|(0xff<<8);
        //add every two bits
        result=(x&mask1)+((x>>1)&mask1);
        //add every four bits
        result=(result&mask2)+((result>>2)&mask2);
        //add every eight bits
        //result=(result&mask3)+((result>>4)&mask3);
        result=(result+(result>>4))&mask3;
        //add every sixteen bits
        //result=(result&mask4)+((result>>8)&mask4);
        result=(result+(result>>8))&mask4;
        //add every thirty two bits
        //result=(result&mask5)+((result>>16)&mask5);
        result=(result+(result>>16))&mask5;
        return result;
}

//注意,该题也为补充题目,查离散数学真值表,由德摩尔根律可以得到结果
/*

  • bitAnd - x&y using only ~ and |
  • Example: bitAnd(6, 5) = 4
  • Legal ops: ~ |
  • Max ops: 8
  • Rating: 1
    */
int bitAnd(int x, int y) {
  return ~((~x)|(~y));
}

//同为补充题,题面的大概意思是返回第几个字节的数
/*

  • getByte - Extract byte n from word x
  • Bytes numbered from 0 (LSB) to 3 (MSB)
  • Examples: getByte(0x12345678,1) = 0x56
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 6
  • Rating: 2
    */
//比较简单直接上思路了:最后用&255析取出一个字节的数,那么将该字节的数转换到最低位就行了
 //注意一点小细节,最低位是从0开始的,n<<3代表*8,转换为字节位数的整数倍
int getByte(int x, int n) {
  return (x>>(n<<3))&255;
}

下为浮点数题目,给出题面

/*

  • floatScale2 - Return bit-level equivalent of expression 2*f for
  • floating point argument f.
  • Both the argument and result are passed as unsigned int’s, but
  • they are to be interpreted as the bit-level representation of
  • single-precision floating point values.
  • When argument is NaN, return argument
  • Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
  • Max ops: 30
  • Rating: 4
    */
unsigned floatScale2(unsigned uf) {
  return 2;
}

/*

  • floatFloat2Int - Return bit-level equivalent of expression (int) f
  • for floating point argument f.
  • Argument is passed as unsigned int, but
  • it is to be interpreted as the bit-level representation of a
  • single-precision floating point value.
  • Anything out of range (including NaN and infinity) should return
  • 0x80000000u.
  • Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
  • Max ops: 30
  • Rating: 4
    */
int floatFloat2Int(unsigned uf) {
  return 2;
}

/*

  • floatPower2 - Return bit-level equivalent of the expression 2.0^x
  • (2.0 raised to the power x) for any 32-bit integer x.
  • The unsigned value that is returned should have the identical bit
  • representation as the single-precision floating-point number 2.0^x.
  • If the result is too small to be represented as a denorm, return
    1. If too large, return +INF.
  • Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while
  • Max ops: 30
  • Rating: 4
    */
unsigned floatPower2(int x) {
    return 2;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值