# CSAPP-Labs

Online class: https://www.bilibili.com/video/BV1iW411d7hd

My code warehouse: https://github.com/Lyb-code/CSAPP-Labs

## Lab1 DataLab

### 1 code

```//1
/*
* bitXor - x^y using only ~ and &
*   Example: bitXor(4, 5) = 1
*   Legal ops: ~ &
*   Max ops: 14
*   Rating: 1
*/
int bitXor(int x, int y) {
int z = x & y; // Bit[1, 1] -> 1
int w = (~x) & (~y); // Bit[0, 0] -> 1
return (~z) & (~w); // Bit[1, 0], [0, 1] -> 1
}
/*
* tmin - return minimum two's complement integer
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 4
*   Rating: 1
*/
int tmin(void) {
int x = (0x80) << 24;
return x;
}
//2
/*
* isTmax - returns 1 if x is the maximum, two's complement number,
*     and 0 otherwise
*   Legal ops: ! ~ & ^ | +
*   Max ops: 10
*   Rating: 1
*/
int isTmax(int x) { // Tmax + 1 = 0x10000000 = ~Tmax. Remember to exclude the case of x = -1.
int k = x + 1;
int m = k ^ (~x);// when x = -1 or Tmax, m = 0
return (!!k) & !m;
}
/*
* allOddBits - return 1 if all odd-numbered bits in word set to 1
*   where bits are numbered from 0 (least significant) to 31 (most significant)
*   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 12
*   Rating: 2
*/
int allOddBits(int x) {
int k = 0xAA;
k = (k << 8) | k;
k = (k << 16) | k;//0xAAAAAAAA
x = x & k; // remove all even-numbered bits of x
return ! (x ^ k);
}
/*
* negate - return -x
*   Example: negate(1) = -1.
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 5
*   Rating: 2
*/
int negate(int x) {
return (~x) + 1;
}
//3
/*
* isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
*   Example: isAsciiDigit(0x35) = 1.
*            isAsciiDigit(0x3a) = 0.
*            isAsciiDigit(0x05) = 0.
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 15
*   Rating: 3
*/
int isAsciiDigit(int x) {
int a = (x ^ 0x30) >> 4;
int b = (x & 0x8) >> 3;
int c = (x & 0x4) >> 2;
int d = (x & 0x2) >> 1;
return ! ((a) | (b & c) | (b & d));// return 1 if a = 0 And b & c = 0 And c & d = 0;
}
/*
* 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 a = !x; // [x->a]  0->1, others->0
a = (a << 1 | a);
a = (a << 2 | a);
a = (a << 4 | a);
a = (a << 8 | a);
a = (a << 16 | a);
return ((~a) & y) + (a & z);
}
/*
* isLessOrEqual - if x <= y  then return 1, else return 0
*   Example: isLessOrEqual(4,5) = 1.
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 24
*   Rating: 3
*/
int isLessOrEqual(int x, int y) {
int k = 0x80 << 24;
int hbx = x & k; // keep only the highest bit of x
int hby = y & k; // keep only the highest bit of y
int hbEqual = !(hbx ^ hby);// if highest bits are equal, return 1
int z = x + (~y) + 1;// x - y;
int ans1 = (!hbEqual) & ((hbx >> 31) & 1);// if hbEqual = 0, use hbx to judge to prevent overflow of z.
int ans2 = hbEqual & (((z >> 31) & 1) | (!(z ^ 0)));
return ans1 + ans2;
}
//4
/*
* 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) {
x = (x >> 16) | x;
x = (x >> 8) | x;
x = (x >> 4) | x;
x = (x >> 2) | x;
x = (x >> 1) | x;
return (~x) & 1;
}
/* howManyBits - return the minimum number of bits required to represent x in
*             two's complement
*  Examples: howManyBits(12) = 5
*            howManyBits(298) = 10
*            howManyBits(-5) = 4
*            howManyBits(0)  = 1
*            howManyBits(-1) = 1
*            howManyBits(0x80000000) = 32
*  Legal ops: ! ~ & ^ | + << >>
*  Max ops: 90
*  Rating: 4
*/
int howManyBits(int x) {
int b16, b8, b4, b2, b1;
int sign = x>>31; // all 1 or all 0
x = ((~sign) & x) | (sign & (~x));// x < 0 --> ~x ; x > 0 --> x;
b16 = (!!(x >> 16)) << 4;// If the upper 16 bits have 1, at least the lower 16(1<<4) bits are required.
x = x >> b16;
b8 = (!!(x >> 8)) << 3;// If the remaning top 8 bits have 1, at least the lower 8(1<<3) bits are required.
x = x >> b8;
b4 = (!!(x >> 4)) << 2;// narrow the scope
x = x >> b4;
b2 = (!!(x >> 2)) << 1;
x = x >> b2;
b1 = (!!(x >> 1));
x = x >> b1;
return b16 + b8 + b4 + b2 + b1 + x + 1;
}
//float
/*
* floatScale2 - 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
*/
unsigned floatScale2(unsigned uf) {
int sign = 0x80000000 & uf;
int exp = (0x7f800000 & uf) >> 23;
int frac = 0x7fffff & uf;
if (exp == 0xff) {// NaN and infinity: do nothing

} else if (exp == 0) {// Denormalized value
if ((frac >> 22) == 0) {
frac = frac << 1;
} else {
exp = 1;
frac = (frac << 1) & 0x007fffff;
}
} else {//Normalized value
exp += 1;
}
uf = sign | (exp << 23) | frac;
return uf;
}
/*
* floatFloat2Int - Return bit-level equivalent of expression (int) f
*   for floating point argument f.
*   Argument is passed as unsigned int, but
*   it is to be interpreted as the bit-level representation of a
*   single-precision floating point value.
*   Anything out of range (including NaN and infinity) should return
*   0x80000000u.
*   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
*   Max ops: 30
*   Rating: 4
*/
int floatFloat2Int(unsigned uf) {
int sign = uf >> 31;
int exp = (0x7f800000 & uf) >> 23;
int bias = (1 << 7) - 1;
int E = 0, ans = 0;
int frac = 0x7fffff & uf;
if (exp == 0xff) {// NaN and infinity
return 0x80000000u;
} else if (exp == 0) {// Denormalized value
E = 1 - bias;
} else {//Normalized value
E = exp - bias;
frac |= 0x800000;
}
//printf("%d %d \n", E, frac);
if (E > 30) { // prevent left shift overflow
return 0x80000000u;
} else if (E > 23) {
ans = frac << (E - 23);
} else if (E > -9) {// prevent the right shift length from being greater than 32
ans = frac >> (23 - E);
}
if (sign) {
ans = -ans;
}
return ans;
}
/*
* floatPower2 - Return bit-level equivalent of the expression 2.0^x
*   (2.0 raised to the power x) for any 32-bit integer x.
*
*   The unsigned value that is returned should have the identical bit
*   representation as the single-precision floating-point number 2.0^x.
*   If the result is too small to be represented as a denorm, return
*   0. If too large, return +INF.
*
*   Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while
*   Max ops: 30
*   Rating: 4
*/
unsigned floatPower2(int x) {
int bias = 127;
if (x > 128) {
return 0x7f800000;
} else if (x > -150) {
x += bias;
if (x >= 0) { // Normalize
return x << 23;
} else { // Denormalize
return 1 << (23 + x);
}

} else {
return 0;
}
}
```

### 2 code description

• allOddBits constructs an odd all 1 mask k

• The idea of isAsciiDigit is to see whether the formal parameter x is in the form of "0x3m", and M is between 0 and 9.

I don't think the promotion of this is strong. When the scope becomes larger, it will be difficult to do this again. Detailed explanation of DataLab of CSAPP The link provides a more generalized solution, as follows:

```int isAsciiDigit(int x) {
int sign = 0x1<<31;
int upperBound = ~(sign|0x39);//The sign changes from positive to negative after adding a number greater than 0x39
int lowerBound = ~0x30;//Plus a value less than or equal to 0x30 is negative
upperBound = sign&(upperBound+x)>>31;
lowerBound = sign&(lowerBound+1+x)>>31;
return !(upperBound|lowerBound);
}
```
• The idea of conditional is correct, but it can be more concise.!! x is very useful.

```int conditional(int x, int y, int z) {
x = !!x; // 0->0, others->1
x = ~x + 1; //The complement of 0 is all 0, and the complement of 1 is all 1
return (x & y) + ((~x) & z);
}
```
• isLessOrEqual idea: different symbols, large positive numbers; The symbols are the same. Look at the difference symbol

• Logical neg idea: use or operation to compress all 1s to the first place.

Can be more concise, as follows. The properties of complement are used: the complement of 0 and Tmin (all 0 after 1) is itself, and the complement of other integers is their opposite number. Only when x is 0, the symbol bit of X and its complement or operation will be 0, and in other cases, it will be 1

```int logicalNeg(int x) {
return ((x | (~x + 1)) >> 31) & 1 ^ 1;
}
```
• howManyBits, get stuck with one of my questions. The idea is to find the highest bit n different from the sign bit, and then add 1 to get n+1

First, we do a process. If the sign bit of x is 0, x remains unchanged; Otherwise, reverse x. The goal of problem solving is to find the highest digit n, and then add 1 to this digit.

Constantly judge whether the highest 16, 8, 4, 2, 1 bit and the lowest 1 bit of X have 1. Use * *** It is convenient to judge whether the binary number contains 1. If the highest 16 bits have 1, the lowest 16 bits must be added. Add 16 to the answer, and move x 16 bits to the right to view the next highest 8 bits... If the highest 16 bits do not have 1, then x does not move to the right, and directly look at the highest 8 bits of the lower 16 bits of X... And so on. The realization is very ingenious. I didn't expect it at first.

• floatScale2, floatfloatfloat2int and floatPower2 investigate floating point numbers, which are smoother than expected, because operators such as if and while can be used. The key is to understand the structure of floating-point numbers and know what normalize value and normalize value are. You can look at online classes or books and discuss them according to the implementation. See code and notes for details.

When the length of the displacement operation is greater than or equal to the window length, the movement obtained is (displacement length% window length), which is known from the bullet screen and can be verified again when reading. Undefined Behavior: Shift amount < 0 or ≥ word size. Therefore, do not make the shift number less than 0 or greater than the window length. I excluded these two cases in the floatFloat2Int method.

• For other functions, just look at the code and refer to the comments

### 3 Summary

CMU teacher said "any form of search is cheating", so the experiment must be done by yourself!!!! First find information and watch online classes. Before the last step, don't look at other people's codes.

Except for howManyBits, I have solved all the problems myself. I am more familiar with bit operation and floating-point representation, which is still good. howManyBits really has no ideas. It draws on the answers of netizens. So I cheated a little (4 / 36).

Pay attention to the experimental summary, enjoy the process of thinking and summary, and learn more excellent code.

This experiment takes 22.5h.

Tags: C

Posted on Fri, 22 Oct 2021 09:23:52 -0400 by logicsound