深入理解计算机第二次实验(LAB2-datalab)

LAB2-datalab

先贴出啦本次实验代码,rating 1,2,3的部分就不写分析了,看简单的注释应该看的懂。
主要是部分rating4的。
先贴代码

/* 
 * CS:APP Data Lab 
 * 
 * 
 * YuanYou shi , 201708010303
 * bits.c - Source file with your solutions to the Lab.
 *          This is the file you will hand in to your instructor.
 *
 * WARNING: Do not include the  header; it confuses the dlc
 * compiler. You can still use printf for debugging without including
 * , although you might get a compiler warning. In general,
 * it's not good practice to ignore compiler warnings, but in this
 * case it's OK.  
 */

#if 0
/*
 * Instructions to Students:
 *
 * STEP 1: Read the following instructions carefully.
 */

You will provide your solution to the Data Lab by
editing the collection of functions in this source file.

INTEGER CODING RULES:
 
  Replace the "return" statement in each function with one
  or more lines of C code that implements the function. Your code 
  must conform to the following style:
 
  int Funct(arg1, arg2, ...) {
      /* brief description of how your implementation works */
      int var1 = Expr1;
      ...
      int varM = ExprM;

      varJ = ExprJ;
      ...
      varN = ExprN;
      return ExprR;
  }

  Each "Expr" is an expression using ONLY the following:
  1. Integer constants 0 through 255 (0xFF), inclusive. You are
      not allowed to use big constants such as 0xffffffff.
  2. Function arguments and local variables (no global variables).
  3. Unary integer operations ! ~
  4. Binary integer operations & ^ | + << >>
    
  Some of the problems restrict the set of allowed operators even further.
  Each "Expr" may consist of multiple operators. You are not restricted to
  one operator per line.

  You are expressly forbidden to:
  1. Use any control constructs such as if, do, while, for, switch, etc.
  2. Define or use any macros.
  3. Define any additional functions in this file.
  4. Call any functions.
  5. Use any other operations, such as &&, ||, -, or ?:
  6. Use any form of casting.
  7. Use any data type other than int.  This implies that you
     cannot use arrays, structs, or unions.

 
  You may assume that your machine:
  1. Uses 2s complement, 32-bit representations of integers.
  2. Performs right shifts arithmetically.
  3. Has unpredictable behavior when shifting an integer by more
     than the word size.

EXAMPLES OF ACCEPTABLE CODING STYLE:
  /*
   * pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
   */
  int pow2plus1(int x) {
     /* exploit ability of shifts to compute powers of 2 */
     return (1 << x) + 1;
  }

  /*
   * pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
   */
  int pow2plus4(int x) {
     /* exploit ability of shifts to compute powers of 2 */
     int result = (1 << x);
     result += 4;
     return result;
  }

FLOATING POINT CODING RULES

For the problems that require you to implent floating-point operations,
the coding rules are less strict.  You are allowed to use looping and
conditional control.  You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants.

You are expressly forbidden to:
  1. Define or use any macros.
  2. Define any additional functions in this file.
  3. Call any functions.
  4. Use any form of casting.
  5. Use any data type other than int or unsigned.  This means that you
     cannot use arrays, structs, or unions.
  6. Use any floating point data types, operations, or constants.


NOTES:
  1. Use the dlc (data lab checker) compiler (described in the handout) to 
     check the legality of your solutions.
  2. Each function has a maximum number of operators (! ~ & ^ | + << >>)
     that you are allowed to use for your implementation of the function. 
     The max operator count is checked by dlc. Note that '=' is not 
     counted; you may use as many of these as you want without penalty.
  3. Use the btest test harness to check your functions for correctness.
  4. Use the BDD checker to formally verify your functions
  5. The maximum number of ops for each function is given in the
     header comment for each function. If there are any inconsistencies 
     between the maximum ops in the writeup and in this file, consider
     this file the authoritative source.

/*
 * STEP 2: Modify the following functions according the coding rules.
 * 
 *   IMPORTANT. TO AVOID GRADING SURPRISES:
 *   1. Use the dlc compiler to check that your solutions conform
 *      to the coding rules.
 *   2. Use the BDD checker to formally verify that your solutions produce 
 *      the correct answers.
 */


#endif
/* 
 * bitAnd - x&y using only ~ and | 
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) { // & = ~(~ | ~)
  x = ~x;
  y = ~y;
  x = x | y;
  return ~x;
}
/* 
 * 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
 */
int getByte(int x, int n) { // wei yi :  x >> 2^3n yan ma 0xff(255)
  n = n << 3;
  x = x >> n;
  x = x & 0xff;
  return x;
}
/* 
 * logicalShift - shift x to the right by n, using a logical shift
 *   Can assume that 0 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3 
 */
int logicalShift(int x, int n) {
  /*x = x >> n;*/
  int yama = 0x1 << 31;
  yama = yama >> n;
  yama = ~(yama << 1);
  return (x >> n)&yama;
}
/*
 * bitCount - returns count of number of 1's in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
00000001 00000001 00000001 00000001
10011010

 */
int bitCount(int x) {// bu dui 
/*  int varCounter = 0;
  int counter = 32;
  while(counter--){
    varCounter += x & 1;
    x = x >> 1;
  }
  return varCounter;*/
  int table = ( ( (0x01 << 8) | 0x01) << 8 | 0x01 ) << 8 | 0x01;
  int counter = x & table;
  counter += (x>>1) & table;
  counter += (x>>2) & table;
  counter += (x>>3) & table;
  counter += (x>>4) & table;
  counter += (x>>5) & table;
  counter += (x>>6) & table;
  counter += (x>>7) & table;
  counter = counter + (counter >>16);
  counter = counter + (counter >>8);
  return counter & 0xff;
}
/* 
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int bang(int x) { 
  x = (~x+1) | x;
  return (~(x >> 31)) & 0x1;
}
/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
  return 0x1<<31;
}
/* 
 * fitsBits - return 1 if x can be represented as an 
 *  n-bit, two's complement integer.
 *   1 <= n <= 32
 *   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
	eg (5,3) : 0000 0101 => 0
	           1111 1011 
	eg (4,3) : 0000 0100 => 1
                   1111 1100
	eg (7,4) : 0000 0111 => 1
		   1111 1001
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 *   
 */
int fitsBits(int x, int n) {
  int left = 32 + ( ~n + 1 ) ;// 32 - n
  int tempx = x << left;
  tempx = tempx >> left; // kan (32-n) shi bu shi fu hao
  return !(x ^ tempx);
}
/* 
 * divpwr2 - Compute x/(2^n), for 0 <= n <= 30
 *  Round toward zero
 *   Examples: divpwr2(15,1) = 7, divpwr2dic(-33,4) = -2
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 */
int divpwr2(int x, int n) {
    /*return x>>n;*/
/*  int yama = x >> 31;
  int tempx = ~x + 1;
  return ( (yama &( (~(tempx >> n)+1) |0x80000000) ) ) | (~yama & (x >> n) );*/
  int yanma = x >> 31;
  x += yanma & ((1 << n) + ~0) ;
  return x >> n;
}
/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return ~x+1;
}
/* 
 * isPositive - return 1 if x > 0, return 0 otherwise 
 *   Example: isPositive(-1) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 8
 *   Rating: 3
 */
int isPositive(int x) {
  return !((x>>31) | !x);
}
/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
	return (y-x)>0 => ( y+(~x+1) ) > 0
	kao lv zheng fu yi chu
	zheng yi chu return 1
	fu yi chu return 0
 */
int isLessOrEqual(int x, int y) { // bu tai d
/*  y = y + (~x+1);
  return !(y >> 31);*/
/*  int sign =! ( ((~x+1)>>31) ^ (y >> 31) );
  int zheng = sign & !(y >> 31);
  int fu = sign & (y >> 31);
  int tempy = y + (~x+1);
  fu = fu & !(tempy>>31);
  zheng = zheng & (tempy>>31);
  return (zheng | !fu & !(y>>31) | !(y ^ x));
*/
int sy = (y>>31);
int sign = (x >> 31) ^ sy;
int tempy = y + (~x+1);
return ( (sign & (x>>31)&1 ) | (!sign & !((tempy>>31)&1) ) | (!(x^y)) );
}
/*
 * ilog2 - return floor(log base 2 of x), where x > 0
 *   Example: ilog2(16) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 90
 *   Rating: 4
32>n>=0
0     0     0     0     0
1     1     1     1     1 00000
16    8     4     2     1
ffff  ff    f     3     1

dui ying xiang jia
 */
int ilog2(int x) {
  int table = 0x0;

  int sign = !!(x >> 16);
  table += sign << 4;
  x = x >> (table & 16);

  sign = !!(x >> 8);
  table += sign << 3;
  x = x >> (table & 8);

  sign = !!(x >> 4);
  table += sign << 2;
  x = x >> (table & 4);

  sign = !!(x >> 2);
  table += sign << 1;
  x = x >> (table & 2);

  sign = !!(x >> 1);
  table += sign ;

  return table;
}
/* 
 * float_neg - Return bit-level equivalent of expression -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 representations of
 *   single-precision floating point values.
 *   When argument is NaN, return argument.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 10
 *   Rating: 2
unsigned result;
    unsigned tmp;
    result=uf ^ 0x80000000; // 
    tmp=uf & (0x7fffffff);
     if(tmp > 0x7f800000)// nan
        result = uf;
    return result;
 */
unsigned float_neg(unsigned uf) {
  unsigned s = (~uf)&0x80000000;
  unsigned exp = uf & (0x7fffffff);
  if(exp > 0x7f800000)// nan
    return uf;
  else
    return uf & 0x7fffffff | s;
}
/* 
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4


0x1234
00000000 00000000 00010010 00110100
1.00100010
10010001 10100000 00000000 00000000
00100011 01000000 00000000 00000000
                  00000001 11111111
                  00000001 00000000
                  00000011 00000000
00000000000000000000000000000000011


1111111 11111111 1111111 1 11111111
00000000
11111111
1 10000000


	        s     exp                    frac
	float : 1   11111111      11111111 11111111 1111111
                0   10001011      00100011 01000000 0000000
        exp = frac.length + 127

 */
unsigned float_i2f(int x) {
  if (!x)
    return 0;
  unsigned sign = x &(0x1<<31);
  unsigned frac=x, tmp=0, flag=0,exp=0;
  if(x < 0){
    frac = -x;
  }
  while (1)
  {
    tmp=frac;
    frac<<=1;
    exp++;
    if (tmp & 0x80000000) break;
  }

  if ((frac & 0x01ff)>0x0100)
    flag=1;
  else if ((frac & 0x03ff)==0x0300)
    flag=1;
  return sign + ((159-exp)<<23) + (frac>>9) + flag;
}
/*
 *   float_twice - 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
	        s     exp                    frac
	float : 1   11111111      11111111 11111111 1111111
	s    = 8000 0000
    exp  = 7f80 0000
	frac = 007f ffff
 */
unsigned float_twice(unsigned uf) {
  unsigned s = 0x80000000 & uf;
  unsigned exp =  0x7f800000 & uf;
  unsigned frac = 0x007fffff & uf;
  if(!exp){
    uf = s | (frac << 1);
  }else if(exp != 0x7f800000){
    uf += 0x00800000;
  }
  return uf;
}

简述rating4

bang

Rating 4 的题目如bang,需要知道的是2进制补码的一些特征。对于任何一个x(除零外)x和-x中必然有一个数的符号位为1.所以直接比较x|-x的符号位即可。
int bang(int x) {
x = (~x+1) | x;
return (~(x >> 31)) & 0x1;
}

bitcount

对于题目bitCount 和 ilog2 其实本质上是一样的,如果我们暴力便利一遍32位就很直接得到问题的解,但是既然题目有限制我们的操作数目,所以就要优化,如何在不用依次遍历32次的情况就可以得到问题的解。
所以这部分其实就要靠算法的知识了。既然遍历32遍很慢,我们就要考虑问题的突破口在哪里?
bitCount题目是要统计1的个数,那么我们最朴素的想法是每次看最低位是不是1,然后右移,直到移动完31次,那么我们用分治的想法,如果把高16位和低16位分开,这样每次右移就可同时判断出两个。问题再分解:把32位分成4个8位,当然也可继续再分解,但是学过分治法就知道,算法的复杂度取决于 分解问题的复杂度 + 合并问题的复杂度 + 解决问题的复杂度。所以我们没有必要再继续分解。所以bitCount的函数很自然的就是如下:

int bitCount(int x) { 
  int table = ( ( (0x01 << 8) | 0x01) << 8 | 0x01 ) << 8 | 0x01;
  int counter = x & table;
  counter += (x>>1) & table;
  counter += (x>>2) & table;
  counter += (x>>3) & table;
  counter += (x>>4) & table;
  counter += (x>>5) & table;
  counter += (x>>6) & table;
  counter += (x>>7) & table;
  counter = counter + (counter >>16);
  counter = counter + (counter >>8);
  return counter & 0xff;
}

这里有个巧妙的地方是算法思想中没有体现的,就是我们用一个count的4个8bit作为每段的计数器,这样得到和的时候只需要“对折”这个counter两次就可以
相当于 count(32位) = counter1(8位) + counter2(8位) + counter3(8位) + counter4(8位)

ilog2

而ilog2也有着同样巧妙的地方。
对于一个int型的x取以2为底的对数。最大为31,最小为0。(因为题目要求x的取值为0x7fffffff~0x00000001)而这个题目的本质其实位最高位‘1‘在哪里
这两个特征允许我们用一个5位长的位串(定义为table)就可表示0到31的位就可以。如:10111(2)=23(10)这样我们就很好做题了
依旧是二分法:

  1. 看高16位有没有‘1‘,如果有的话table的第4为置为1,否则为0
  2. 如果table的第4位为1,则看高16位中的高8位是否有‘1‘,有的话table的第三位置为1,否则为0.如果table[4] = 0,则看低16位中的高8位是否有1。
  3. 依次类推,每次缩小范围但优先看高位
    这样问题规模小到查找的位串长为1的时候结束。这样能保证每次找到的是这个位串最高位。
    很自然的写出代码:
int ilog2(int x) {
  int table = 0x0;

  int sign = !!(x >> 16); // 查找最高位是否有1
  table += sign << 4;      // 找到有1,则把table的第4位置为1
  x = x >> (table & 16);  //  找到有1,舍弃第16位,没找到不舍

  sign = !!(x >> 8);
  table += sign << 3;
  x = x >> (table & 8);

  sign = !!(x >> 4);
  table += sign << 2;
  x = x >> (table & 4);

  sign = !!(x >> 2);
  table += sign << 1;
  x = x >> (table & 2);

  sign = !!(x >> 1);
  table += sign ;

  return table;
}

看到代码中有些地方的处理,每次查询table对应的位置是不是1就可以,最后table表示的就是结果,舍弃低位是为了方便下次的查找,不需要判断应该去哪半段找1,直接在当前已经截取好的位串中取高n位就可以。

float_i2f

float_i2f方法其实要简单很多,不需要二分法,直接做就可以了,就是需要考虑一下float型的进位和舍弃的问题。
做这道题之前要清楚一个问题:float在计算机中是怎么表示的。
一个32位的float中 有一个符号位,8位表示阶码,23位尾数
那么一个int型的数如:0x1234转换位float需要四步

(0x1234 = (000000000001001000110100)(int) = (0(s) 10001011(exp) 001000110100(frac) )(float)
  1. 确定符号位 s: 0
  2. 确定阶码exp:127 + frac.length(尾数的长)
  3. 确定尾数frac:舍弃最高位的1的后面
  4. 做舍入处理:如果第三步得到的frac长大于23,则作舍入处理。舍入原则如果把第23位和后面要舍入的直接加个小数点,若小数点之后大于0.5则入,若小于0.5则舍去,若等于0.5则考虑小数点前一位,使得摄入之后小数点前一位为0。
unsigned float_i2f(int x) {
  if (!x)
    return 0;
  unsigned sign = x &(0x1<<31);
  unsigned frac=x, tmp=0, flag=0,exp=0;
  if(x < 0){
    frac = -x;
  }
  while (1)
  {
    tmp=frac;
    frac<<=1;
    exp++;
    if (tmp & 0x80000000) break;
  }

  if ((frac & 0x01ff)>0x0100)
    flag=1;
  else if ((frac & 0x03ff)==0x0300)
    flag=1;
  return sign + ((159-exp)<<23) + (frac>>9) + flag;
}

看到代码
第一步特判,如果是零,直接返回。
这里要注意,获取exp和frac都是在while中(此时的frac在32中的最高位向低位的位置即31位到8位的位置,此时的exp是保存了int型的x在有效的数前有多少位的零,所以后面求exp的时候是127-(32 - exp) 也就是159-exp),而获取符号在while之前。
最后一个if和else判断则是判断尾数舍入的问题。(如x=0x1234时,舍入之前frac 后8位到0位要是有数字就要判断舍入,而此时舍入要求的0.5对应的恰好为0x100。else if中的0x300 就是判断是否是1.5,此时要进位)

你可能感兴趣的:(课程作业)