Bootstrap

第一次实验

题目和解答都在代码里:

/*
 * CS:APP Data Lab
 *
 * bits.c - Source file with your solutions to the Lab.
 *          This is the file you will hand in to your instructor.
 *
 */
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tests.h"
/*
 * Instructions to Students:
 *
 * STEP 1: Fill in the following struct with your identifying info.
 */

#if 0
/*
 * STEP 2: Read the following instructions carefully.
 */

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

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.

  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;
  }
#endif

/*
 * STEP 3: Modify the following functions according the coding rules.
 *
 */
/* NO:1
 * 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));
}

/* NO:2
 * bitNor - ~(x|y) using only ~ and &
 *   Example: bitNor(0x6, 0x5) = 0xFFFFFFF8
 *   Legal ops: ~ &
 *   Max ops: 8
 *   Rating: 1
 */
int bitNor(int x, int y) {
  return (~x)&(~y);
}
/* NO:3
 * copyLSB - set all bits of result to least significant bit of x
 *   Example: copyLSB(5) = 0xFFFFFFFF, copyLSB(6) = 0x00000000
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int copyLSB(int x) {
  return (x<<31)>>31;
}
/* NO:4
 * evenBits - return word with all even-numbered bits set to 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 8
 *   Rating: 2
 */
int evenBits(void) {
  int x=0x55;
  int result=0;
  result|=x;
  result|=x<<8;
  result|=x<<16;
  result|=x<<24;
  return result;
}
/* NO:5
 * logicalShift - shift x to the right by n, using a logical shift
 *   Can assume that 1 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int logicalShift(int x, int n) { 
  return (~((1<<31)>>(n-1)))&(x>>n);
}
/* NO:6
 * 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>>16;
  x|=x>>8;
  x|=x>>4;
  x|=x>>2;
  x|=x>>1;
  return (~x)&1;
}
/* NO:7
 * leastBitPos - return a mask that marks the position of the
 *               least significant 1 bit. If x == 0, return 0
 *   Example: leastBitPos(96) = 0x20
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 4
 */
int leastBitPos(int x) {
  return ((~x)+1)&x;
}
/* NO:8
 * TMax - return maximum two's complement integer
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmax(void) {
  int x=~(1<<31);
  return x;
}
/* NO:9
 * negate - return -x
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return (~x)+1;
}
/* NO:10
 * 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);
}
/* NO:11
 * isNonNegative - return 1 if x >= 0, return 0 otherwise
 *   Example: isNonNegative(-1) = 0.  isNonNegative(0) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 3
 */
int isNonNegative(int x) {
  return !(x>>31);
}
/* NO:12
 * sum3 - x+y+z using only a single '+'
 *   Example: sum3(3, 4, 5) = 12
 *   Legal ops: ! ~ & ^ | << >>
 *   Max ops: 16
 *   Rating: 3
 */
/* A helper routine to perform the addition.  Don't change this code */
static int sum(int x, int y) {
  return x+y;
}
int sum3(int x, int y, int z) {
  int word1 = 0;
  int word2 = 0;
  /**************************************************************
     Fill in code below that computes values for word1 and word2
     without using any '+' operations
  ***************************************************************/
  word1=(x^y)^z;
  word2=((x&y&z)|((~word1)&(x|y|z)))<<1;
  /**************************************************************
     Don't change anything below here
  ***************************************************************/
  return sum(word1,word2);
}
/* NO:13
 * addOK - Determine if can compute x+y without overflow
 *   Example: addOK(0x80000000,0x80000000) = 0,
 *            addOK(0x80000000,0x70000000) = 1,
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3
 */
int addOK(int x, int y) {
  int t=x+y;
  int sx=x>>31;
  int sy=y>>31;
  int st=t>>31;
  return !((~(sx^sy))&(sx^st));
}
/* NO:14
 * abs - absolute value of x (except returns TMin for TMin)
 *   Example: abs(-1) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 10
 *   Rating: 4
 */
int abs(int x) {
  int sx=x>>31;
  return (x&(~sx))|(((~x)+1)&sx);
}
/* NO:15
 * isNonZero - Check whether x is nonzero using
 *              the legal operators except !
 *   Examples: isNonZero(3) = 1, isNonZero(0) = 0
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 10
 *   Rating: 4
 */
int isNonZero(int x) {
  return (((((~x)+1)^x)|x)>>31)&1;
}
蛋疼的实验报告,表示不会用wps

一、 函数分析

1. int bitAnd(int x, int y);

函数实现:

int bitAnd (int x, int y) {

  return ~((~x) | (~y));

}

函数分析:

由德摩根定律得:~(x & y) = (~x) | (~y) 所以:x & y = ~((~x) | (~y)) 

 

2. int bitNor (int x, int y);

函数实现:

Int bitNor(int x,int y){

return (~x)&(~y);

}

函数分析:

  由德摩根定律得:~(x|y)=(~x)&(~y)    

3. Int copyLSB(int x);

函数实现:

Int copyLSB(int x){

return (x<<31)>>31;

}

函数分析:只要注意是算术右移即可

4.Int evenBits(int x);

函数实现:

Int evenBits(int x){

 int x=0x55;

 Int result=0;

 result|=x;

 result|=x<<8;

 result|=x<<16;

 result|=x<<24;

 return result;

}

函数分析:0x5501010101,分别左移0(不移动),8,16,24位就可以将第

1,2,3,4个字节都设为01010101,即所有的偶数字节都是1

5.Int logicalShift(int x,int n);

 Int logicalShift(int x,int n){

   return (~((1<<31)>>(n-1)))&(x>>n);

 }

函数分析:1<<31产生最高为是1,其余位全是0的数,其值右移n-1位再取反得到覆盖原来x且不覆盖算术右移高位补的1的掩码,再和x>>n相与即可

    6.int bang(int x);

 int bang(int x) {

  x|=x>>16;

  x|=x>>8;

  x|=x>>4;

  x|=x>>2;

  x|=x>>1;

  return (~x)&1;

}

函数分析:首先一个数只要有1,就应该返回0,全为0返回1,那么很自然想到要将每一位相或,不过如果是一位一位地或,需要操作31次,因此想到了折半的方法,第一次移16位,那么前16位的1相当于存到了后16位和原先后16位的1并存,相当于改变了运算次序并用了结合律,依次类推。

8位二进制数为例,假设这个数位表示是a1,a2,a3,a4,a5,a6,a7,a8

第一次移4位:(15)(26)(37)(48

第二次移2位:((15)(37))((26)(48))

最后:(((15)(37))((26)(48)))

(为了方便,直接用i代表ai)

7.int leastBitPos(int x);

int leastBitPos(int x) {

  return ((~x)+1)&x;

}

函数分析:设最低位为i,那么0i-1都是0,~xx位相反,0i-1都是1,那么对(~x)+1来说,0i-1都是0,第i位是1i+131位与x相反,那么与x相与直接可得i位的掩码

8.int tmax(void);

int tmax(void) {

  return ~(1<<31);

}

函数分析:INT_MAX就是除了第32位是0,其余都是1的数

9.int negate(int x);

int negate(int x) {

  return (~x)+1;

}

函数分析,即求补码,也就是求反加1

10.int isPostive(int x);

int isPositive(int x) {

  return (!(x>>31))&(!!x);

}

函数分析:由于最高位是符号位,!(x>>31)1时,x>=0,0时,为0时,x<0;现在要排除x=0的情况,只有x!=0时,!!x=1,因此两式相与即可

11.int isNonNegative(int x);

int isNonNegative(int x) {

  return !(x>>31);

}

函数分析:同上

12.static int sum(int x, int y);

static int sum(int x, int y) {

  return x+y;

}

int sum3(int x, int y, int z) {

  int word1 = 0;

  int word2 = 0;

      word1=(x^y)^z;

      word2=((x&y&z)|((~word1)&(x|y|z)))<<1;

      return sum(word1,word2);

}

函数分析:思路是先做一次不进位的加法,然后用sum把进位加上去。

x^y^z相当于是不进位加法,下面对某一位分析进位:当x,y,z中有两个或三个1时产生进位,这时令相应的位为1,最后左移1位相加即可。x&y&z是三个都是1的情况,~word1021x|y|z是至少有一个1,这样就判断了进位

13.int addOK(int x, int y);

int addOK(int x, int y) {

  int t=x+y;

  int sx=x>>31;

  int sy=y>>31;

  int st=t>>31;

  return !((~(sx^sy))&(sx^st));

}

函数分析:sx表示用x的符号位填满32位,y,z一样,函数应当在x,y同号但x+yx异号时返回0,否则返回1

14.int abs(int x);

int abs(int x) {

  int sx=x>>31;

  return (x&(~sx))|(((~x)+1)&sx);

}

函数分析:函数在x>0x=TMIN时返回x,在x<0x!=TMIN)时返回-x(即取反加1),那么需要用符号位来控制两者只有一个被返回

15.int isNonZero(int x)

int isNonZero(int x) {

  return (((((~x)+1)^x)|x)>>31)&1;

}

函数分析:(((~x)+1)^x)|x得到从最低的1位到32位全是1其余全是0的数(对于0来说是全0),那么右移31位让其最高位与1相与即可



;