书是要看的,但实验也是要做的!接下来将《深入理解计算机系统》里面的几个实验做一下,巩固一下理论知识。
数据实验。这个实验要求学生们实现简单的逻辑和算术函数,但是只能使用一个高度受限的c的子集。比如,他们必须只能用位级操作来计算一个数字的绝对值。这个实验帮助学生们了解c数据类型的位级表示,和数据操作的位级行为。
说实话,这个实验对于有些人可能会很有兴趣,因为它属于智力型实验。有点像奥林匹克数学竞赛上面的题目。如果以后不是从事太过于底层的工作,实验的过程了解一下就行了。
bits.c的代码如下:
- /*
- * 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.
- *
- * WARNING: Do not include the <stdio.h> header; it confuses the dlc
- * compiler. You can still use printf for debugging without including
- * <stdio.h>, 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.
- */
- #include "btest.h"
- #include <limits.h>
- /*
- * Instructions to Students:
- *
- * STEP 1: Fill in the following struct with your identifying info.
- */
- team_struct team =
- {
- /* Replace this with your full name */
- "lycos",
- /* Replace this with your Andrew login ID */
- "ac00"
- };
- #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;
- }
- 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. 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.
- #endif
- /*
- * STEP 3: 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 btest test harness to check that your solutions produce
- * the correct answers. Watch out for corner cases around Tmin and Tmax.
- */
- /*
- * bitAnd - x&y using only ~ and |
- * Example: bitAnd(6, 5) = 4
- * Legal ops: ~ |
- * Max ops: 8
- * Rating: 1
- */
- int bitAnd(int x, int y) {
- /* 狄摩根定律
- (A∪B)’=A’∩B’ (A∩B)’=A’∪B’
- 其中A’表示集合A对全集的补集*/
- return ~((~x)|(~y));
- }
- /*
- * bitXor - x^y using only ~ and &
- * Example: bitXor(4, 5) = 1
- * Legal ops: ~ &
- * Max ops: 14
- * Rating: 2
- */
- int bitXor(int x, int y) {
- /* 狄摩根定律
- (A∪B)’=A’∩B’ (A∩B)’=A’∪B’
- 其中A’表示集合A对全集的补集*/
- return (~(~x&~y))&(~(x&y));
- }
- /*
- * evenBits - return word with all even-numbered bits set to 1
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 8
- * Rating: 2
- */
- int evenBits(void) {
- /*置所有偶数为为1,则得到0x55555555即可*/
- int i = 0x55;
- return (i << 24) | (i << 16) | (i << 8) | i;
- }
- /*
- * 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) {
- return 0xff & (x >> (n << 3));
- }
- /*
- * bitMask - Generate a bitmask consisting of all 1's
- * from lowbit to highbit and 0's everywhere else.
- * Examples: bitMask(5,3) = 0x38
- * Assume 0 <= lowbit <= 31, and 0 <= highbit <= 31
- * If lowbit > highbit, then mask should be all 0's
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 16
- * Rating: 3
- */
- int bitMask(int highbit, int lowbit) {
- /* 生成一个int值bitmask,它的lowbit到highbit位之间为1
- 其余位为0,返回bitmask
- 注意,最后还要&上(i << lowbit)以防止lowbit大于highbit的情况*/
- int i = ~0;
- //return ((i << ( highbit + 1)) ^ (i << lowbit)) & (i << lowbit);
- return (((i << highbit) << 1) ^ (i << lowbit)) & (i << lowbit);
- }
- /*
- * reverseBytes - reverse the bytes of x
- * Example: reverseBytes(0x01020304) = 0x04030201
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 25
- * Rating: 3
- */
- int reverseBytes(int x) {
- return ((x>>24)&0xff) | (((x>>16)&0xff)<<8) |
- (((x>>8)&0xff)<<16) | ((x&0xff)<<24);
- /* 我觉得下面的做法也行!因为左移时无论啥种情况,都补0.
- ((x>>24)&0xff) | ((x>>16)&(0xff<<8)) |
- ((x<<8)&(0xff<<16)) | (x<<24)
- */
- }
- /*
- * 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) {
- /* 技巧性相当高!利用了补码的特性,
- x的补码中有效位为1的最低的位置是一个特殊的位置,
- 它之前的位与x相反,之后的为全为0*/
- return (~x+1)&x;
- //这个x&(x^(x+(~0)))也不错!
- }
- /*
- * logicalNeg - implement the ! operator, using all of
- * the legal operators except !
- * Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
- * Legal ops: ~ & ^ | + << >>
- * Max ops: 12
- * Rating: 4
- */
- int logicalNeg(int x) {
- /* 它使用了0的特性~x+1 == ~x*/
- return ((~(~x+1)&(~x))>>31)&1;
- }
- /*
- * 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) {
- /*First shift the x by n and clean the first k bits of "1" caused by the sign bit. B/c we know how many bits we
- * shifted, then we know how many bits we need to clean.
- */
- int i = 1 << 31;
- return ((~(i>>(n+(~0))))&(x>>n)&(!(!n)<<31>>31))|(((!n)<<31>>31)&x);
- }
- /*
- * minusOne - return a value of -1
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 2
- * Rating: 1
- */
- int minusOne(void) {
- /* 0xffffffff的值就是-1*/
- return ~0;
- }
- /*
- * tmin - return minimum two's complement integer
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 4
- * Rating: 1
- */
- int tmin(void) {
- /* TMIN is 1 followed by 31 zeros */
- return (1 << 31);
- }
- /*
- * TMax - return maximum two's complement integer
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 4
- * Rating: 1
- */
- int tmax(void) {
- return ~(1 << 31);
- }
- /*
- * 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) {
- //0以及0x80000000的特性:~x+1
- //错误答案:return !((x>>31)&0x1);
- return (~x>>31)&((~x+1)>>31)&0x1 ;
- }
- /*
- * isLess - if x < y then return 1, else return 0
- * Example: isLess(4,5) = 1.
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 24
- * Rating: 3
- */
- int isLess(int x, int y) {
- int xsign = (x >> 31) & 0x1;
- int ysign = (y >> 31) & 0x1;
- /* 分为三种情况:
- 1,x > 0 ,y < 0;
- 2, x > 0 ,y > 0;或x < 0,y < 0;(利用y-x是否为0求)
- 3, x < 0 ,y > 0
- */
- //return (xsign & ~ysign) | !(((~x+1+y)>>31)&0x1) & !(~xsign & ysign);
- /*
- *上述答案有一个小bug,那就是x == y时它返回1,与要求不符。正解如下
- *((xsign & ~ysign) | !((~x+y)>>31)) & !(~xsign & ysign)。
- */
- return (xsign & ~ysign) | !(((~x+y)>>31)&0x1) & !(~xsign & ysign);
- }
- /*
- * sm2tc - Convert from sign-magnitude to two's complement
- * where the MSB is the sign bit
- * Example: sm2tc(0x80000005) = -5.
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 15
- * Rating: 4
- */
- int sm2tc(int x) {
- /*首先理解题意:sign-magnitude为有符号数,two's complement为二进制补码表示
- * 0x80000005为一个有符号数,-5的二进制补码为0xfffffff3 ,我们要做的就是把
- * 0x80000005 ——> 0xfffffff3
- */
- int sign = x >> 31;
- return (x ^ sign) + (((1 << 31) + 1) & sign);
- //其他答案:return (sign & (~(x ^ (x & (1 << 31))) + 1)) | (~sign & x);
- }
- /*
- * tc2sm - Convert from two's complement to sign-magnitude
- * where the MSB is the sign bit
- * You can assume that x > TMin
- * Example: tc2sm(-5) = 0x80000005.
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 15
- * Rating: 4
- */
- int tc2sm(int x) {
- /*首先理解题意:sign-magnitude为有符号数,two's complement为二进制补码表示
- * 0x80000005为一个有符号数,-5的二进制补码为0xfffffff3 ,我们要做的就是把
- * 0xfffffff3 ——> 0x80000005
- */
- int sign = (x>>31) & 0x1;
- return 2;
- }
- /*
- * 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) {
- /*If x isn't zero, either x or -x is negative*/
- int ret = ~x + 1;
- ret = ret | x;
- return (ret >> 31) & 1;
- }
- /*
- * 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) {
- /* exploit arithmetic right shift */
- int a = x >> 31;
- int b = x ^ a;
- return b + (~a + 1);
- }
- /*
- * 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) {
- int mask = !x;
- mask = (mask << 31) >> 31;
- return (mask & z) | (~mask & y);
- }
- /*
- * isEqual - return 1 if x == y, and 0 otherwise
- * Examples: isEqual(5,5) = 1, isEqual(4,5) = 0
- * Legal ops: ! ~ & ^ | + << >>
- * Max ops: 5
- * Rating: 2
- */
- int isEqual(int x, int y) {
- /*
- * My solution 1:
- *
- * int ret = x + (~y + 1);
- *
- * return !ret;
- *
- * which check if x-y==0 (overflow does not matter),but it used
- * too much operators.Later I found that x^y==0 if and only if x==y.
- * So here is My Solution 2:
- */
- return !(x ^ y);
- }
每个函数看起来都很简单,如果用心做的话也是要花不少时间的。。。