1. 程式人生 > >第一次實驗

第一次實驗

題目和解答都在程式碼裡:

/*
 * 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相與即可