CSAPP实验(1)---datalab

实验目的:

通过此次实验,熟悉整型及浮点数的位表达形式,通过位运算了解常用二进制运算的方法。

实验过程:

通过题目要求通过位运算完成INTEGER - 整数部分:bitXor、tmin、isTmax、allOddBits、negate
、isAsciiDigit、conditional、isLessOrEqual、logicalNeg、howManyBits以及FLOAT - 浮点数部分:floatScale2、floatFloat2Int、floatPower2共13个实验

实验原理:

1.bitXor  

/* 
 * 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);
}

实验要求: 实现异或操作

应用德摩根率

2.tmin

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {

  return (0x1<<31);

}

实验要求:返回二进制中的最小值

由于采用二进制补码进行操作,只需将0x1左移31位

3.isMax

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
  
  return !(~(1 << 31) ^ x);

}

实验要求:判断x是否为2进制补码中最大值 

先用~(1<<31)将二进制补码中的最大值表示出来,再将x与二进制中最大值进行按位异或,若x是最大值,则!后为1;若x不是最大值,则!后为0.

4.allOddBits

* allOddBits - return 1 if all odd-numbered bits in word set to 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
 */
int allOddBits(int x) {
  int flag = 1<<1;
  flag =flag|(flag<<2);
  flag =flag|(flag<<4);
  flag =flag|(flag<<8);
  flag =flag|(flag<<16);
  return !((flag&x)^flag);
}

实验要求:二进制下如果所有偶数位都是1则返回1,否则返回0。

先将flag通过取或复制的方式得到 0xAAAAAAAA,之后将flag与x进行&操作,得到的结果奇数位均为0,偶数位数字与x相同;再将结果与flag进行异或,判断x的偶数位是否均为1。

5.negate

* negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x){
  return ~x+1;
}

实验要求:输出相反数

根据二进制补码原理,对x进行取反再加1后即可得到x的相反数。

6.isAsciiDigit

 * 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) {
    //找到关系,42,43不同时为一,前8位为0
    return !(((~0xFF)&x)+((0xF0&x)^0x30)+!((12&x)^12)+!((10&x)^10));
  return 2;
}

实验要求:判断输入数据是否再0x30~0x39

 0x30到0x39之间的数有如下规律:前八位均为零;从低位数第4位和第2位不同时为一;第4位和第3位不同时为一;于是可以进行如上的判断。

7.conditional

* conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
  //先判断x的布尔型
   x=~(!x)+1;//x==0?0xffffffff:0x00000000
     return (y&(~x)|z&x);
}

 实验要求:返回x ? y : z,即若x为真,返回y;若x为假,返回z。

因此该实验要首先判断x的布尔型:将x变为!x的相反数;即若x为真,x的值赋为1;若x为假,x的值赋为0;

8.isLessOrEqual

* isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
  int signx = (x >> 31) ; // 
	  int signy = (y >> 31) ;
	  int signy_x = ((y + ~x + 1) >> 31) ;
	  return (signx & !signy) | (!(signx ^ signy) & !signy_x);//比较符号位是否相同,
}

实验要求:判断两个操作数是否符合小于等于关系:

首先,比较x和y的符号位是否相同;

signy_x = ((y + ~x + 1) >> 31)表示(y-x)的符号位

若x,y符号为不同,通过(signx & !signy)即可返回正确结果;若x,y符号位相同,则(!(signx ^ signy)为1 ,此时若y大于等于x,则!signy_x也为1;若y小于等于x,则!signy_x为0;综上可以输出正确结果

9.logicalNeg

int logicalNeg(int x) {
  return ((x|(~x+1))>>31)+1;//有符号数执行算术右移,无符号数进行逻辑右移
}

实验要求:实现逻辑!操作 

先进行x|(~x+1)操作,若x非0,则x|(~x+1)最高位一定为1,算术右移31位后得到ffffffff,再加1为0;若x为0,则x|(~x+1)最高位为0,算术右移31位再加1后为1;

故该操作可以实现!操作

10.howManyBits

实验要求:返回在二进制补码中表示 x 所需的最小位数

int howManyBits(int x) {
	  int sign = x >> 31;
	  x = (~sign & x) | (sign & ~x); // (x >= 0) ? x : ~x
     int b16 = (!!(x>>16))<<4;
    x = x >> b16;//,若查找到了,右移16位,继续查找
    int b8 = (!!(x>>8))<<3;
    x = x >> b8;
    int b4 = (!!(x>>4))<<2;
    x = x >> b4;
    int b2 = (!!(x>>2))<<1;
    x = x >> b2;
    int b1 = !!(x>>1);
    x = x >> b1;
    return (1+b1+b2+b4+b8+b16+x);
}

   对于负数,最少位数的二进制表示为一位符号位加上负数取反后的最高位1的位数;对于正数,最少位数的二进制表示为一位符号位加上其最高位1的位数,因此该实验的关键在于判断x中第一个出现1的位置.

   先将x取绝对值,采用类似7.conditional中操作,x= (~sign & x) | (sign & ~x).采用二分查找法。对前16为判断,若其中存在1,将x右移16位继续查找,进行迭代操作.

   最终返回操作次数之和加1即可.

 11.floatScale2

实验要求:对于入参unsgned uf,以float来解释其二进制位,若uf为NaN或INF,直接返回;否则计算uf*2并返回

unsigned floatScale2(unsigned uf) {
   int sign = uf & 0x80000000; 
	  int e = uf & 0x7f800000; 
	  int f = uf & 0x007fffff; 
	  
	  if (e == 0)
	    return (uf << 1) | sign;
	  if (e == 0x7f800000)
	    return uf; 
	  e += 0x00800000;
	  if (e == 0x7f800000)
	    return 0x7f800000 | sign;
	
	  return sign | e | f; // 拼回去

 根据float类型储存规则

分别用sign、e、f取出uf的符号位,指数以及有效数

1.e==0,指数为0,则直接左移1位返回×2后的值;

2.e==0x7f800000,为INF,直接返回uf;

3.将指数×2后判断是否为INF,若为INF,直接返回;若非INF,返回sign|e|f.

12.floatFloat2Int

实验要求:传入一个无符号整数 uf,把它当作单精度浮点数,返回它截断后的整数部分。也就是 (int)uf。如果出现溢出,则返回 0x80000000u

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

分别取出sign,e,f. 这里e是实际的指数.f将省略的1也加上

1.如果uf为0,则返回0

2.如果真正的指数>31,则返回溢出值

3.真正如果的指数小于零则返回零,因为0<uf<1

4.考虑真正的指数和23的大小,进行移位

如果符号相同直接返回原值

如果为负(原来为正),返回溢出值

如果为正(原来为负),返回相反数

13.floatPower2

实验要求:计算浮点数2.0^x;若结果太小返回0,太大返回 +INF

unsigned floatPower2(int x) {
 
int exp = x + 127;
  if(exp <= 0) return 0;
  if(exp >= 255) return 0x7f800000;
  return exp << 23;
}

注记:NAN:not a number//denorm:those numbers very close to zero //INF:infinite

根据float类型编码原理,把x看成真正的指数,exp=x+127;

1.exp<=0,denorm,返回0;

2.exp>=255,INF

3.要返回一个float类型的数,其尾码全为0,因此只需将exp左移23为至指数区即可。

测试数据

实验小结:

作为计科大一学生,没有接触过计算机系统相关知识,初次上手该实验感觉较有趣也富有挑战性,更深层次了解了二进制编码

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南游北归

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值