CS:APP Data Lab Report
Name SUNCHAOYI
Introduction
This report documents the solutions to the CS:APP Data Lab problems. The goal of the lab is to solve a series of programming puzzles under strict constraints, using only a limited set of C operators to manipulate integer and floating-point bit patterns.
Report
-
bitXor
Description: x⊕yx \oplus yx⊕y.
Legal ops:
~ &Solution:
-
Ops = 8
A⊕B=A‾B∪AB‾=A‾B‾∩AB‾‾‾ \begin{align*} A \oplus B &= \overline{A} B \cup A \overline{B} \\ &= \overline{\overline{\overline{A} B} \cap \overline{A \overline{B}}} \\ \end{align*} A⊕B=AB∪AB=AB∩AB
cppint bitXor (int x,int y) { int a = ~((~x) & y); int b = ~(x & (~y)); return ~(a & b); } -
Ops = 7 (Opt.)
A⊕B=(A∪B)∩A∩B‾=A‾∩B‾‾∩A∩B‾ \begin{align*} A \oplus B &= (A \cup B) \cap \overline{A \cap B} \\ &= \overline{\overline{A} \cap \overline{B}} \cap \overline{A \cap B}\\ \end{align*} A⊕B=(A∪B)∩A∩B=A∩B∩A∩B
cppint bitXor (int x,int y) {return ~(~x & ~y) & ~(x & y);}
-
-
tmin
Description: Return minimum two's complement integer.
Legal ops:
! ~ & ^ | + << >>Solution:
cppint tmin (void) {return 1 << 31;} -
isTmax
Description: Returns 1 if xxx is the maximum, two's complement number, and 0 otherwise.
Legal ops:
! ~ & ^ | +Solution:
-
The maximum two's complement integer TmaxT_{\text{max}}Tmax has the property x+1=∼xx + 1 = \sim xx+1=∼x, i.e. (x+1)⊕(∼x)=0(x + 1) \oplus (\sim x) = 0(x+1)⊕(∼x)=0.
-
x=−1x = -1x=−1 is a special case (0xffffffff\texttt{0xffffffff}0xffffffff) that need to be excluded.
cppint isTmax (int x) {return !((~(x + 1)) ^ x) & !!(x + 1);} -
-
allOddBits
Description: Return 1 if all odd-numbered bits in word set to 1.
Legal ops:
! ~ & ^ | + << >>Solution:
Construct a number whose odd-numbered bits are all 1, i.e. the 32-bit pattern 0xAAAAAAAA\texttt{0xAAAAAAAA}0xAAAAAAAA.
-
Ops = 9
cppint allOddBits (int x) { int mask = (0xAA << 24) | (0xAA << 16) | (0xAA << 8) | 0xAA; return !((x & mask) ^ mask); } -
Ops = 7 (Opt.)
cppint allOddBits (int x) { int a = 0xAA << 8; int b = a | 0xAA; int c = b << 16 | b; return !((x & c) ^ c); }
-
-
negate
Description: Return −x-x−x.
Legal ops:
! ~ & ^ | + << >>Solution:
{x+(−x)=0x+(∼x)=−1⟹−x=(∼x)+1 \begin{cases} x + (-x) = 0\\ x + (\sim x) = -1 \end{cases} \Longrightarrow -x = (\sim x) + 1 {x+(−x)=0x+(∼x)=−1⟹−x=(∼x)+1
cppint negate (int x) {return (~x) + 1;} -
isAsciiDigit
Description: Return 1 if 0x30≤x≤0x390x30 \le x \le 0x390x30≤x≤0x39 (ASCII codes for characters
0to9).Legal ops:
! ~ & ^ | + << >>Solution:
-
Upper 24 bits must be zero.
-
Bits 4-7 must equal
0011. -
Lower 4 bits must be in range
0000to1001. (Check whether bit 3 is 0 to have more detailed classification.) -
Ops = 14
cppint isAsciiDigit (int x) { int a = !(x >> 8); int b = !(x >> 4 ^ 0x3); int low = x & 0xF; int c = !(low >> 3) | !(low >> 1 ^ 0x4); return a & b & c; } -
Ops = 7 (Opt.)
-
No need to use variable aaa to checker upper 24 bits.
-
use +6 to bound lower 4 bits within
1111.
cppint isAsciiDigit (int x) { int a = x >> 4 ^ 3; int b = ((x & 0xF) + 6) >> 4; return !(a | b); } -
-
-
conditional
Description: Same as
x ? y : z.Legal ops:
! ~ & ^ | + << >>Solution:
-
Convert any non-zero xxx to boolean.
-
Create a mask that is either all zeros (0x00000000\texttt{0x00000000}0x00000000) or all ones (0xFFFFFFFF\texttt{0xFFFFFFFF}0xFFFFFFFF).
-
Use the mask to select between −y-y−y and −z-z−z.
-
Ops = 14
cppint conditional (int x,int y,int z) { int op = !!x; int a = (~op) + 1; int b = (~a) & ((~y) + 1); // when mask = 0x00000000, b = -y; otherwise b = 0 int c = a & ((~z) + 1); // when mask = 0xFFFFFFFF, c = -z; otherwise c = 0 return y + z + b + c; } -
Ops = 8 (Opt.)
cppint conditional (int x,int y,int z) { int mask = (~(!!x)) + 1; return (y & mask) | (z & (~mask)); // one side must equal to 0 }
-
-
isLessOrEqual
Description: If x≤yx \le yx≤y then return 1, else return 0.
Legal ops:
! ~ & ^ | + << >>Solution:
- Different signs: If xxx is negative and yyy is non-negative, then x≤yx \leq yx≤y is always true.
- Same signs: We can safely compute y−xy - xy−x without overflow and check if it's non-negative.
cppint isLessOrEqual (int x,int y) { int signx = x >> 31 & 1; int signy = y >> 31 & 1; int diff = signx ^ signy; int a = diff & signx; int b = !diff & !((y + ((~x) + 1)) >> 31); // y - x >= 0 return a | b; } -
logicalNeg
Description: Implement the
!operator using all of the legal operators except!.Legal ops:
~ & ^ | + << >>Solution:
-
If x=0x = 0x=0, both xxx and −x-x−x have sign bit 0. Otherwise either xxx or −x-x−x have sign bit 1.
-
x∣(−x)x | (-x)x∣(−x) is 0x00000000\texttt{0x00000000}0x00000000 or 0xFFFFFFFF\texttt{0xFFFFFFFF}0xFFFFFFFF, just add 1 to solve it.
cppint logicalNeg (int x) {return ((x | ((~x) + 1)) >> 31) + 1;} -
-
howManyBits
Description: Return the minimum number of bits required to represent xxx in two's complement.
Legal ops:
! ~ & ^ | + << >>Solution:
-
For x<0x < 0x<0 find the highest 0-bit, x≥0x \ge 0x≥0 find the highest 1-bit. Use
x ^ (x >> 31)to transform xxx into the latter case. -
Use divide-and-conquer approach for the most significant 1-bit, and finally add the sign bit.
cppint howManyBits (int x) { int b16,b8,b4,b2,b1,b0; x = x ^ (x >> 31); b16 = (!!(x >> 16)) << 4; x >>= b16; b8 = (!!(x >> 8)) << 3; x >>= b8; b4 = (!!(x >> 4)) << 2; x >>= b4; b2 = (!!(x >> 2)) << 1; x >>= b2; b1 = !!(x >> 1); x >>= b1; b0 = x; return b16 + b8 + b4 + b2 + b1 + b0 + 1; // sign } -
-
floatScale2
Description: Return bit-level equivalent of expression 2×f2 \times f2×f for floating point argument fff.
Legal ops: Any integer/unsigned operations incl.
||,&&. Alsoif,while.Solution:
-
Extraction the sign bit, exponent field and fraction field.
-
When exp=0xFFexp = \texttt{0xFF}exp=0xFF, just return it; When exp=0x00exp = \texttt{0x00}exp=0x00, frac×2frac \times 2frac×2; otherwise exp+1exp + 1exp+1.
cppunsigned floatScale2 (unsigned uf) { unsigned sign = uf >> 31 & 0x1; unsigned exp = (uf >> 23) & 0xFF; unsigned frac = uf & 0x7FFFFF; if (exp == 0xFF) return uf; else if (exp == 0x0) frac <<= 1; else ++exp; return (sign << 31) | (exp << 23) | frac; } -
-
floatFloat2Int
Description: Return bit-level equivalent of expression (int) fff for floating point argument fff.
Legal ops: Any integer/unsigned operations incl.
||,&&. Alsoif,while.Solution:
Converting to integer with truncation:
int(f)={0if ∣f∣<1trunc(1.f×2e−127)if 1≤∣f∣<231INT_MINotherwise (overflow) \text{int}(f) = \begin{cases} 0 & \text{if } |f| < 1 \\ \text{trunc}\left(1.f \times 2^{e-127}\right) & \text{if } 1 \leq |f| < 2^{31} \\ \text{INT\_MIN} & \text{otherwise (overflow)} \end{cases} int(f)=⎩ ⎨ ⎧0trunc(1.f×2e−127)INT_MINif ∣f∣<1if 1≤∣f∣<231otherwise (overflow)Where truncation is implemented by:
- When E≥23E \geq 23E≥23: 1.f×2E=(1.f×223)×2E−231.f \times 2^{E} = (1.f \times 2^{23}) \times 2^{E - 23}1.f×2E=(1.f×223)×2E−23
- When E<23E < 23E<23: Right shift discards fractional bits, i.e. >>(23−E)>> (23 - E)>>(23−E)
cppint floatFloat2Int (unsigned uf) { unsigned sign = uf >> 31 & 0x1; unsigned exp = (uf >> 23) & 0xFF; unsigned frac = uf & 0x7FFFFF; int E,M; E = exp - 127; if (E < 0) return 0; if (E >= 31) return 0x80000000u; M = (1 << 23) | frac; if (E >= 23) M <<= E - 23; else M >>= 23 - E; return sign ? -M : M; } -
floatPower2
Description: Return bit-level equivalent of the expression 2.0x2.0^x2.0x (2.0 raised to the power xxx).
Legal ops: AAny integer/unsigned operations incl.
||,&&. Alsoif,while.Solution:
-
Case 1 : Overflow
x>Emax=e−127=254−127=127x > E_{\max} = e - 127 = 254 - 127 = 127x>Emax=e−127=254−127=127
return 0b01111111100...0\texttt{0b01111111100...0}0b01111111100...0, i.e. 0x7F800000\texttt{0x7F800000}0x7F800000
-
Case 2 : Normalized
e=E+127∈[1,254]⟹E∈[−126,127]e = E + 127 \in [1,254] \Longrightarrow E \in [-126,127]e=E+127∈[1,254]⟹E∈[−126,127]
V=1.0×2e−127V = 1.0 \times 2^{e - 127}V=1.0×2e−127
f=0,V←(e<<23)∣ff = 0,\quad V \gets (e << 23) | ff=0,V←(e<<23)∣f
-
Case 3 : Denormalized
e=0e = 0e=0
V=0.f‾×2−126=2x⟹0.f‾=2x+126V = \overline{0.f} \times 2^{-126} = 2^x \Longrightarrow \overline{0.f} = 2^{x + 126}V=0.f×2−126=2x⟹0.f=2x+126
minimum number is 2−126×2−23=2−1492^{-126} \times 2^{-23} = 2^{-149}2−126×2−23=2−149, i.e. put 1 on index 0.
⟹V←1<<(x+149)\Longrightarrow V \gets 1 << (x + 149)⟹V←1<<(x+149)
-
Case 4 : Underflow
x<−149x < -149x<−149, return 0
cppunsigned floatPower2 (int x) { if (x < -149) return 0; else if (x > 127) return 0x7F800000; else if (x >= -126) return (x + 127) << 23; else return 1 << (x + 149); } -
Correctness Results Perf Results
Points Rating Errors Points Ops Puzzle
1 1 0 2 7 bitXor
1 1 0 2 1 tmin
1 1 0 2 8 isTmax
2 2 0 2 7 allOddBits
2 2 0 2 2 negate
3 3 0 2 7 isAsciiDigit
3 3 0 2 8 conditional
3 3 0 2 14 isLessOrEqual
4 4 0 2 5 logicalNeg
4 4 0 2 32 howManyBits
4 4 0 2 12 floatScale2
4 4 0 2 16 floatFloat2Int
4 4 0 2 9 floatPower2
Score = 62/62 [36/36 Corr + 26/26 Perf] (128 total operators)