- /*
- * 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 (~0)+!(x&1);
- #if 0
- [Solution of Problem 3]
- Using ~0 we can get an 0xFFFFFFFF;
- If the LSB, which is the bit deciding whether the number is even or not, is equal to 1,
- the number should be odd and the answer should be 0xFFFFFFFF(~0),
- so we add nothing.
- If the LSB is equal to 0,
- the number should be even and the correct answer should be 0,
- which is equal to 0xFFFFFFFF+1,
- so we can add 1 to 0xFFFFFFF.
- In order to figure out whether the number is odd or even,
- we can use x%2, or x&1.
- So the correct answer should be (~0)+!(x&1);
- 4 ops used.
- #endif
- }
- /* NO:4
- * evenBits - return word with all even-numbered bits set to 1
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 8
- * Rating: 2
- */
- int evenBits(void) {
- int p=0x55;
- p=(p<<8)+p;
- p=(p<<16)+p;
- return p;
- #if 0
- [Solution of Problem 4]
- I think this solution is not so concise, but I do not have any better ideas.
- Firstly, we manually set a int p as 0x55(01010101 in binary).
- Then, we double it by (p<<8)+p and get 0xAAAA.
- Finally, we double it again and get 0x55, which is the answer we want.
- 4 ops used.
- #endif
- }
- /* 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) {
- int p=(1<<31)&x;// Getting the sign bit.
- int u=x^p;//Changing the sign bit
- u>>=n;//Right move the u
- p=(!!p)<<30>>n<<1;//Add back the sign bit
- return u|p;
- #if 0
- [Solution of Problem 5]
- Firstly, we can simply get the sign bit by BitAnd x and 0x40000000(1<<31).
- After this operation, if the sign bit is 1, then set p to 0x40000000(1<<31).
- Otherwise, the p will be 0;
- Then, we can use u=x^p to get a number which is equal to p but the sign bit is set to 0.
- Then, when shr u, the logical shifting result will be equal to the result of arithmetic one.
- Finally we try to add the deleted sign bit back to new u. We need to shr the p logically, too.
- This process is same as shl 1 by (31-n). However, the '-' is forbidden.
- So we can <<31 and >>n. But it will reset the sign bit causing arithmetic shr.
- So we divide this process into 3 parts: <<30, >>n, and <<1 finally. And get an acceptable answer.
- 10 ops used.
- #endif
- }
- /* 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|(x>>16);
- x=x|(x>>8);
- x=x|(x>>4);
- x=x|(x>>2);
- x=x|(x>>1);
- return (~x)&1;
- #if 0
- [Solution of Problem 6]
- Maybe the simple thought is to find whether a bit is non-zero bit by bit.
- Because of limited operations, like problem 4, we need to cut the length of x half and half to reduce the steps.
- So we using shr to cut half and | it with the original one. As the result, the last bit will be the OR result of all bits.
- We can use &1 to get the last bit.
- 12 ops used.
- #endif
- }
- /* 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&(~x+1);
- #if 0
- [Solution of Problem 7]
- There is a feature about "plus one" in binary.
- When we add 1 to a number in binary, we always reset all the non-zero bits after the first zero bit from the right.
- Then we change that zero bit into one.
- And this problem is similar. We need to change the first non-zero bit like the following process:
- x=[XXXX100...00] -> y=[XXXX000...00] -> ans=x^y=[0000100...00]
- ^ ^ ^
- The most difficult part is how to get the y above. What we need is to borrow the "plus-one" process to finish this task.
- We can using ~x as a springboard.
- x=[XXXX100...00] -> ~x=[PPPP011...11] -> ~x+1=[PPPP100...00]
- ^ ^ ^
- It may hard to get y when we found we are here. But you may observe (~x+1)&x is the correct answer.
- That is all.
- 4 ops used.
- #endif
- }
- /* NO:8
- * TMax - return maximum two's complement integer
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 4
- * Rating: 1
- */
- int tmax(void) {
- return ~(1<<31);
- #if 0
- [Solution of Problem 8]
- That is 01111..11, which is equal to ~10000..0;
- 2 ops used.
- #endif
- }
- /* NO:9
- * negate - return -x
- * Example: negate(1) = -1.
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 5
- * Rating: 2
- */
- int negate(int x) {
- return (~x)+1;
- #if 0
- [Solution of Problem 9]
- As we know, -p=~p+1;
- For example, -1=[111...11]=[111...10]+1=~[000..01]+1=~(1)+1;
- 1=[000...01]=[000...00]+1=~[111..11]+1=~(-1)+1;
- //BTW: [...] means in binary.
- 2 ops used.
- #endif
- }
- /* 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)&(!(x>>31));
- #if 0
- [Solution of Problem 10]
- Firstly, get the sign bit as problem 5;
- Then using ! twice to change 0x40000000 to 1 while 0 to 0.
- However, we need to check the an special situation that x==0.
- 0 is not positive, we need to & the answer given above with !!x to fix this.
- 6 ops used.
- #endif
- }
- /* 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);
- #if 0
- [Solution of Problem 11]
- The same as the previous problem but we do not need to care about 0.
- 4 ops used.
- #endif
- }
- /* 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)|(y&z)|(z&x))<<1;
- #if 0
- [Solution of Problem 12]
- I have read the book of Digital Logic about the adder. When we need to get c=a+b, we need to:
- 1.Half add: It is the same as c[i]+=a[i]^b[i];
- 2.Carry: if a[i]==b[i]==1, then c[i+1]++;
- We always repeatly accomplish this two processes bit by bit, because the c[i] may be changed when carrying.
- This problem provide us an opportunity to add. We may separate the two procedures into word1&2, then we can get the plus answer like:
- word1=x^y;
- word2=(x&y)<<1
- When there is 3 numbers needed to be added, it become confusing.
- We should redefine the half-adder and the carrier. A table may help:
- x[i]+y[i]+z[i] word1[i] word2[i+1] TruthNumber
- 00 0 0 0
- 01 1 0 1
- 10 0 1 2
- 11 1 1 3
- We know a fact that when we XOR some bool values, the answer is whether the number of truth in them is odd or even.
- So the word1 should be x^y^z;
- So word2? If more than 2 truths exist, the result should be 1. So we can enumerate all the situation and get:
- word2=((x&y)|(y&z)|(z&x))<<1;
- That is all.
- 8 ops used.
- #endif
- /**************************************************************
- 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 p1=!(x>>31),p2=!(y>>31),p3=!((x+y)>>31);
- return (p1^p2) | (!(p1^p3));
- #if 0
- [Solution of Problem 13]
- Firstly, get the sign digits of x,y,x+y as p1, p2 and p3.
- Then check p1, p2, p3 by:
- if p1 != p2, then return 1;
- else if p1,p2!=p3 return 0;
- return 1;
- We can use xor to accomplish the same effect, that is return (p1^p2) | (!(p1^p3));
- 11 ops used.
- #endif
- }
- /* NO:14
- * abs - absolute value of x (except returns TMin for TMin)
- * Example: cus_abs(-1) = 1.
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 10
- * Rating: 4
- */
- int cus_abs(int x) {
- int condition=!(x>>31);
- int value_when_true=x;
- int value_when_false=(~x)+1;
- int mask=condition+(~0);
- return (~mask&value_when_true) | (mask&value_when_false);
- #if 0
- [Solution of Problem 14]
- Amazingly, we find it intersting that we can accomplish a 'myIf' using 5 ops by:
- int myIf(int condition=...,/*0 or 1*/,int value_when_true=...,int value_when_false...)
- {
- int mask=condition+(~0);
- return (~mask&value_when_true) | (mask&value_when_false);
- /*
- This uses a feature that bin[11111..11]+1=bin[000000..0].
- And we know[11111..11]&x=x while [00000..00]&x=0.
- */
- }
- Using this "myIf" we all know this question is as same as:
- myIf(x>0,x,-x);
- We can simply use the solution of the previous problems to calculate x>0 and -x.
- 10 ops used.
- #endif
- }
- /* 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) {
- int n=~x+1;
- return ((n>>31)|(x>>31))&1;
- #if 0
- [Solution of Problem 15]
- I do not have any thoughts for a long time so I search the answer online.
- As we know, only when x=0 can we get x==-x. When talking about "Two's complement", only when x=0 can we get the last bit of x is equal to -x.
- So we can get the solution.
- 6 ops used.
- #endif
- }
- int main(){
- int a,n;
- int i,Case;
- int result = 0;
- srand((unsigned)time(NULL));
- //function NO:1
- result=0;
- Case=1;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- if(bitAnd(x , y) != test_bitAnd(x,y))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",bitAnd(x , y), test_bitAnd(x,y));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO2
- result=0;
- Case=2;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- if(bitNor(x , y) != test_bitNor(x,y))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",bitAnd(x , y), test_bitAnd(x,y));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO3
- result=0;
- Case=3;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if(copyLSB(x) != test_copyLSB(x))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",copyLSB(x), test_copyLSB(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO4
- result=0;
- Case=4;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- if(evenBits() != test_evenBits())
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",evenBits(), test_evenBits());
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO5
- result=0;
- Case=5;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()%31;
- if(logicalShift(x , y) != test_logicalShift(x,y))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",logicalShift(x , y), test_logicalShift(x,y));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO6
- result=0;
- Case=6;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if(bang(x) != test_bang(x))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",bang(x), test_bang(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO7
- result=0;
- Case=7;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if(leastBitPos(x) != test_leastBitPos(x))
- {
- result = 1;
- printf("[Wrong! with %d got %d != %d]\n",x,leastBitPos(x ), test_leastBitPos(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO8
- result=0;
- Case=8;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if( tmax() != test_tmax())
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",tmax(), test_tmax());
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO9
- result=0;
- Case=9;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if(negate(x ) != test_negate(x))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",negate(x ), test_negate(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO10
- result=0;
- Case=10;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if(isPositive(x) != test_isPositive(x))
- {
- result = 1;
- printf("[Wrong! with %d got %d != %d]\n",x,isPositive(x), test_isPositive(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO11
- result=0;
- Case=11;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- if(isNonNegative(x ) != test_isNonNegative(x))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",isNonNegative(x), test_isNonNegative(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO12
- result=0;
- Case=12;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- int z = rand()-RAND_MAX/2;
- if(sum3(x , y,z) != test_sum3(x,y,z))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",sum3(x , y,z), test_sum3(x,y,z));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO13
- result=0;
- Case=13;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- if(addOK(x , y) != test_addOK(x,y))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",addOK(x , y), test_addOK(x,y));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO14
- result=0;
- Case=14;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- if(cus_abs(x ) != test_abs(x))
- {
- result = 1;
- printf("[Wrong! with %d != %d]\n",cus_abs(x ), test_abs(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- //function: NO15
- result=0;
- Case=15;
- for(i = 0; i < 1000000; i++)
- {
- int x = rand()-RAND_MAX/2;
- int y = rand()-RAND_MAX/2;
- if(isNonZero(x ) != test_isNonZero(x))
- {
- result = 1;
- printf("[Wrong! with %d got %d != %d]\n",x,isNonZero(x ), test_isNonZero(x));
- break;
- }
- }
- if(result != 0)
- printf("NO.%d. Result is wrong with test case:%d\n",Case,result);
- else
- printf("NO.%d. All Passed!\n",Case);
- return 0;
- }
Tests.h代码已折叠 展开折叠内容
|
---|
显示/移除行号
|