CSAPP上的实验还是十分有趣的,尤其是其自动评分系统。做完了实验之后自己也确实对知识的理解更加深入了。有关CSAPP的知识以后或许我会再写博客,现在则先把实验写写博客吧
百度网盘下载实验文档
提取码:kdx4
实验 题1-2
//1
采用学过的摩尔定律分解即可
int bitXor(int x, int y) {
return ~(~(x&~y)&(~(~x&y)));
}
很容易理解
int tmin(void) {
return 1<<31;
题3-6
//2
这个我做错了,不能用<<我没看到-.-
int isTmax(int x) {
return !(x^(~(1<<31)));
}
正确解法之一:
int isTmax(int x)
{
return !((x + 1) ^ ~x) & !!(x + 1);
}
//这个我的ops超了,不是优解
int allOddBits(int x) {
int flag=0xAA;
return !((flag&x)^flag)&!((flag<<8&x)^(flag<<8))&!((flag<<16&x)^(flag<<16))&!((flag<<24&x)^(flag<<24));
}
相反数取反加一即可,对于Tmin没用
int negate(int x) {
return ~x+1;
}
题7-9
//3
0x30=>00110000
0x39=>00111001
假设其二进制位分别是a1...a8
可以知道a1-a4是永远不变的,如果不同就可以直接pass掉了,当a5等于1时,则a6 a7必须都为0
当a5等于0时则随意
int isAsciiDigit(int x) {
int tmp=0xf;
return (!((~tmp&x)^0x30))&((!((1<<3)&x))|((!(2&x))&(!(4&x))));
}
因为要返回y或者z,可以想到需要用+运算符,利用0xffffffff+1等于0,同时自己去
与运算不会改变,而0做与运算则正好全为0
int conditional(int x, int y, int z) {
int tmp=(!!x+(~0));
return (~tmp&y)+(tmp&z);
}
可以想到利用y+~x+1来得到y-x,之后判断其正负即可,但是
需要考虑到溢出的情况,考虑到溢出只有两种情况,即x与y异号,分类讨论即可。
int isLessOrEqual(int x, int y) {
int tmp=y+(~x+1);
int tmp1=!!((1<<31)&x)&!((1<<31)&y);
int tmp2=!!((1<<31)&x)|!((1<<31)&y);
return (!((1<<31)&tmp)|tmp1)&tmp2;
}
题10-end
首先通过把最高位为1后的位都填充为1,然后判断最低位是否为一,无论是负数还是整数都至少
有一个bit位为1
int logicalNeg(int x) {
x=(x>>16)|x;
x=(x>>8)|x;
x=(x>>4)|x;
x=(x>>2)|x;
x=(x>>1)|x;
return (x&1)^1;
}
首先从左到右扫描x的bit位
这题极为复杂,我也是看别人的思路写出来的,通过对正数和负数的分析,可以知道
一定是相邻的两个bit异号时得到最高位,其中正数是0 1,其中0是符号位,而负数则相反是 1 0,
其中1是符号位,通过分析可以知道对负数取反后的正数其所求位数与该负数没有区别,于是可以把负数都取反,利用conditional函数可以做到永远得到是正数(0除外),之后根据logicalNel函数里
一样,把最高位1后的所有位都变成1,然后利用bitcount求其1的个数即为所需的位数,当然还需要加1个bit的符号位。其中求bitcount采用了分治的思想,可以减少运算符。
int howManyBits(int x) {
int y=~x;
int tmp1=!((1<<31)&x);
int tmp2=!((1<<31)&y);
tmp1=~tmp1+1;
tmp2=~tmp2+1;
int tmp=(tmp1&x)+(tmp2&y);
tmp=tmp|tmp>>1;
tmp=tmp|tmp>>2;
tmp=tmp|tmp>>4;
tmp=tmp|tmp>>8;
tmp=tmp|tmp>>16;
int mask=1;
mask=(mask<<8)|1;
mask=(mask<<8)|1;
mask=(mask<<8)|1;
int sum=0;
sum+=tmp&mask;
sum+=(tmp>>1)&mask;
sum+=(tmp>>2)&mask;
sum+=(tmp>>3)&mask;
sum+=(tmp>>4)&mask;
sum+=(tmp>>5)&mask;
sum+=(tmp>>6)&mask;
sum+=(tmp>>7)&mask;
return ((sum&0xff)+((sum>>8)&0xff)+((sum>>16)&0xff)+((sum>>24)&0xff))+1;
}
//float
对于单精度浮点数,其最高位为符号位,然后8位指数位,23位底数位,当指数位为0是是非规格化数,此时底数是0.x1x2x3...这样子,当指数位非零时是规格化数,此时底数是1.x1x2x3...这样子
同时当指数位全1时,若是底数位为0则代表无穷大,如果底数不为0,则代表NaN。当然其真正的指数还想需要减去127。由于基本上没有了运算符的限制,所以这后三题多费些时间还是能够做出来的。
unsigned floatScale2(unsigned uf) {
unsigned exp=0;
exp=((0x7fffffff)&uf)>>23;
//cout<>23;
if(exp==0xff)return 0x80000000u;
int e=exp-127;
if(e<0)return 0;
unsigned sum=0;
int tmp=uf&0x7fffff;
for(int i=23;i>=0&&i>=23-e;i--){
sum=sum*2+(tmp>>i);
int shift=(32-i+1);
tmp=tmp<>shift;
if(sum>max)return 0x80000000u;
}
unsigned res=1;
for(int i=1;i<=e;i++){
res*=2;
if(res>max)return 0x80000000u;
}
int ops=(!!((1<<31)&uf)==1)?-1:1;
//cout<max)return 0x80000000u;
return (int)(res+sum)*ops;
}
unsigned floatPower2(int x) {
unsigned ans=0;
int INF=0x7f800000;
if(x<-150)return 0;
if(x>127)return INF;
int exp=x+127;
if(x==-127){
return 0x7fffff;
}
if(x<-127){
int tmp=~x-127;
ans=ans|(1<<(23-tmp+1));
}else{
ans=ans|(exp<<23);
}
return ans;
}
实验结果



