CS:APP Lab1:datalab

CS:APP Lab1:datalab

一.bitXor(x,y)

puzzle分析:

​ 本题要求只用 & 和 ~ 两种操作来实现或运算.或运算可通过代码return (x&~y)|(~x&y)来实现,为避免使用 | 操作,可通过将上式进行变式:

(x&~y)|(~x&y)=~((~x|y)&(x|~y))=~(((~x|y)&x)|((~x|y)&~y))=~((x&y)|(~x&~y))=~(~x&~y)&~(x&y)

就可得到如下实现代码.

实现代码:

int bitXor(int x, int y) {
  	return ~(~x&~y)&~(x&y);
}

二.tmin

puzzle分析:

​ 本题要求通过使用位运算符来求得32位机器最小整数值.易知32位机器表示最小补码的是-231,即符号位为1,后跟31个0.这个运算可以用左移运算实现,即1<<31.

实现代码:

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

三.isTmax(x)

puzzle分析:

​ 本题为判断一整数x是否为最大二进制补码,可根据当最大补码(符号位是0,后跟31个1)加一后会溢出为最小补码,即1后跟31个0,二者各位上数字刚好互补的性质,可通过代码!~(x+(x+1))将二者相加并取反即得到0再求非即得所求的1.但是要注意当x为-1即各位都是1时,加1也会溢出成0,经过上述运算同样得到1的结果,因此得排除-1的输入.因此只需利用!(x+1)=0(当仅当x不等于-1时成立)来为~(x+(x+1))加上偏移即可.

实现代码:

int isTmax(int x) {
  	return !(~(x+(x+1))+!(x+1));
}

四.allOddBits(x)

puzzle分析:

​ 本题要求判断当输入的二进制数x各奇数位都是1时返回1,否则返回0.容易得到:二进制数各奇数位都为1、偶数位都为0时,每4bit位数字分布应为1010(考虑有第0位),转换成16进制就是A,因此奇数位全为1、偶数位全为0的二进制数转换为16进制数就是0xAAAAAAAA.因此只需将x与0xAAAAAAAA进行比较:按位进行"与运算",所得结果在奇数位上数字情况与x一致,偶数位都是0,将这个结果再与0xAAAAAAAA进行位"异或运算",如果每一位都一样,将得到0,取非就是1.(注:由于定义变量只能使用8bit大小的整数,因此要通过移位运算得到整数0xAAAAAAAA.

实现代码:

int allOddBits(int x) {
	int val = 0xAA + (0xAA<<8);//得到0xAAAA
	val = val + (val<<16);//得到0xAAAAAAAA
  	return !((x&val)^val);
}

五.negate(x)

puzzle分析:

​ 本题要求某整数的负数,按照定义可知,按位取反再加1即得.

实现代码:

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

六.isAsciDigit(x)

puzzle分析:

​ 本题要求判断某十六进制数是否在asc码中对应’1’~‘9’.思路:用该数减去0x30,得到非负数(符号位为1);减去0x3a,得到负数(符号位为1),就可判断该数属于这个区间.然而不允许使用符号’-',则可利用上题求负数的思路进行减法运算.再将分别所得结果右移31位得到各自的符号位,然后将之分别与1进行"与运算",再处理并合并即得最终返回结果.

实现代码:

int isAsciiDigit(int x) {
	int a = x+(~0x30+1);
	int b = x+(~0x3A+1);
	a = (a>>31)&0x1;
	b = (b>>31)&0x1;
  	return !a&b;
}

七.conditional

puzzle分析:

​ 本题要求使用给定的运算符实现条件表达式的功能.首先用!!x将输入的x转化位布尔量0或1,取负数得到各位全为1或全为0,再创一个与x有关的参数的反码,分别将二者与输入的y,z进行"与运算"再进行"或运算"合并即可选择性舍弃掉不需要的值.

实现代码:

int conditional(int x, int y, int z) {
	int a = ~(!!x)+1;//得到各位都为1或各位都为0
	int b = ~a;//取反
  	return (y&a)|(z&b);
}

八. isLessOrEqual(x, y)

puzzle分析:

​ 本题要求判断某数是否小于或等于另一数.按常规的思路,只需判断y-x的结果符号位为0还是1,然而在有限位机器中,当x,y异号时可能出现减法溢出情况:

​ 1.y>0且x<0,y-x<0(正溢出)

​ 2.y<0且x>0,y-x>0(负溢出)

因此,分以下情况类型考虑:
1.当x,y同号,不用考虑溢出,直接按常规思维处理;

​ 2.当x,y异号,只需考虑二者各自的符号,拿x为例,x符号位是1说明一定有x<y,x符号位是0,说明一定有x>y.

实现代码:

int isLessOrEqual(int x, int y) {
	int x_sign = x>>31&0x1;
	int y_sign = y>>31&0x1;
	int d = x_sign^y_sign;
	int res = y+(~x+1);
	int sign = (res>>31)&0x1;
  	return (!d&!sign)|(d&x_sign);
}

九.logicalNeg(x)

puzzle分析:

​ 本题要求使用除’!‘之外的运算符来实现求某数的非的功能.根据非零数的负数符号位与该数不同,0与最小补码的负数都是自身的性质,可以根据数x与-x的符号位中是否出现1来判断它是不是非零数.因此用到’|'或运算符将x与-x进行"或运算",只要二者中有一个符号位为1,就说明一定是非零数,此时得到符号位为1的数.再将其算术右移得到全1(表示的值是-1),加1即得0.反之若输入是0,则最终得到全0,加1便得1.

实现代码:

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

十.howManyBits(x)

puzzle分析:

​ 本题要求计算某个数按二进制补码表示所需的最小位数.可计算原数绝对值的编码表示中数值位最高位在第几位.再加上符号位,即为最终所求位数.(因为在Tmin+1~Tmax之间一一对应的数都需要相同位数来表示)

以下为思路:

1.sign = x>>31可获得x的符号;x = (sign&~x)|(~sign&x)是为了消除x的符号位,x为正值不变,x为负得到~x.

2.然后,将32位数字分为两个16位,将x右移16位,看高16位中是否有非零位,若有,则低16位一定是有效位,则总位数+16,再把x右移16位,以便下一步分析高16位的有效位数情况;若没有,则高16位都无效,低16位不全有效,下一步继续分析低十六位.

3.以此类推,逐步分成高低8位,4位,2位,1位,根据判断结果加入总位数中.

4.最终结果再加上符号位即得真正所求的总位数.

(另外,还需考虑0和-1这两种特殊情况,发现沿用上述思路同样成立~~)

实现代码:

int howManyBits(int x) {
	int b16,b8,b4,b2,b1,b0;
	int sign = x>>31;
	x = (sign&~x)|(~sign&x);
	b16 = (!!(x>>16))<<4;
	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));
	x = x>>b1;
	b0 = x;
  	return b16+b8+b4+b2+b1+b0+1;
}

十一. floatScale2(uf)

puzzle分析:

​ 本题要求返回将输入的32位浮点表示数的值按浮点运算规则乘以2得到的32位数.

​ 首先需要提取出32位无符号整型转化为浮点表示时各字段(符号,阶码,小数).要提取出阶码字段,可利用无符号数0 11111111 00000000000000000000000(B),即十六进制下的0x7F800000与输入的uf进行按位与运算,再右移23位即可得到阶码exp = (uf&0x7F800000)>>23(是一个正数).符号字段通过sign = uf&(1<<31)来获取.

根据阶码字段exp的值可分以下几种情况考虑:

​ 1.当exp=0时,表示的值就取决于小数字段,若小数字段为0,则乘以2应返回本身;若非0,则可将小数字段左移一位 (由于除符号位外,其他字段全为0,这里通过右移uf,再并上符号位即可补充舍掉的符号位).

​ 2.当exp=11111111B(即255)时,要么是无穷大,要么是NAN,因此返回自身即可;

​ 3.当exp不为0或255时,要想乘以2只需将exp加一即可(但需要注意当exp为254时,加一则会溢出为无穷大,此时 应返回无穷大,即0x7f800000|sign)

实现代码:

unsigned floatScale2(unsigned uf) {
	int exp = (uf&0x7F800000)>>23;
	int sign = uf&(1<<31);
	if(exp == 0) return (uf<<1)|sign;
	if(exp == 255) return uf;
	if(++exp == 255) return 0x7F800000|sign;
	return (exp<<23)|(uf&0x807FFFFF);
}

十二.floatFloat2Int(uf)

puzzle分析:

浮点数计算公式为: V = (-1)s * M * 2E (M = f+1,E = exp-bias,bias = 2k-1-1)

因此首先计算出s = uf>>31,E = ((uf&07xf800000)>>23)-127,f = (uf&0x007fffff)|0x00800000

(由于f默认隐含1,故将指数段最低位设为1以将其规范化)

下面进行分类:
1.当阶码字段和小数字段全为0(即+0或-0,都是0)时,转换整数就是0.

​ 2.当指数E<0时,值小于1,转换整型后返回0;当E>31时,指数太大无法表示,返回0x80000000.

​ 3.当0<=E<=31时,由于小数字段长23位,故应再分两类:

​ a)E<23,小数字段实际表示的数超过原数,故应对其截断,通过右移(23-E)位来实现;

​ b)E>=23,小数阶段实际表示的数小于原数,故应对其延展,通过左移(E-23)位来实现.

​ 最后处理尾数部分,并检查是否发生了溢出:

​ a)如果尾数的符号与原始浮点数的符号相同,并且没有溢出(即尾数的最高位不是符号位),则返回尾数f;

​ b)如果尾数表示负数且发生了溢出,返回TMIN;

​ c)如果尾数表示正数且发生了溢出,返回TMAX(通过取反加1得到).

实现代码:

int floatFloat2Int(unsigned uf) {
	int s = uf>>31;
	int E = ((uf&0x7f800000)>>23)-127;
	int f = (uf&0x007fffff)|0x00800000;
	if(!(uf&0x7fffffff)) return 0;
	if(E<0) return 0;
	if(E>31) return 0x80000000;
	if(E>23) f<<=(E-23);
	else f>>=(23-E);
	if(!((f>>31)^s)) return f;
	else if(f>>31) return 0x80000000;
	else return ~f+1;
}

十三.floatPower2(x)

puzzle分析:

​ 本题要求计算2的整数幂.由于是2的整数次幂,因此不用考虑小数字段.又由于输入的是指数,可将其加上偏置bias=2^8-1^-1=127来转换成阶码exp.由于规格化数最小只能表示2-126,即exp=1,因此下面针对exp的值进行分类讨论:

​ 1.当exp<=0时,无符号数不能表示该数,此时返回0;

​ 2.当exp>255时,结果太大,不能表示出来,此时返回正无穷;(正无穷+INF通过代码0xff<<23来获得)

​ 3.其他情况下,只需将exp左移23位即可得到2x.

实现代码:

unsigned floatPower2(int x) {
	int INF = 0xff<<23;
	int exp = x + 127;
	if(exp <= 0) return 0;
	if(exp >= 255) return INF;
	return exp<<23;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值