CSAPP DataLab

DataLAb

Posted by Kevin on July 1, 2022

bitXor

1
2
3
4
5
6
7
8
9
10
11
12
/* 
 * 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 a = ~((~x) & y);
  int b = ~((~y) & x);
  return ~(a&b);
}

由于所有运算都是按位的,考虑一位即可

设计:x&(~y)

y/x 0 1
0 0 1
1 0 0

对称的,有:

(~x)&y

y/x 0 1
0 0 0
1 1 0

二者取反后与起来,再取反就是答案。

tmin

1
2
3
4
5
6
7
8
9
10
11
/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
	int x=(1<<31);
  return x;

}

比较容易

isTmax

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * 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) {
	int n1=~0;
	int tmp=!(((x+1)^x)^n1);
	tmp=tmp&(!(!(x^n1)));
  return tmp;
}

自己想的一个怪方法…

!(a^b) : a == b

!(!(a^b)) : a != b(这里需要两次 ! 来保证结果为 0 或 1

~0 : -1

我们判断 x^(x+1) 是否等于 -1

可以发现这样的 x 只能是 Max 或者 -1

于是再判断下 x!=-1 就可以了

allOddBits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 
 * 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 c=0xAA;
  int y=c;
  y=(y<<8)+c;
  y=(y<<8)+c;
  y=(y<<8)+c;
  return !((x&y)^y);
}

令 y= 0xAAAAAAAA

判断 x&y == y

negate

1
2
3
4
5
6
7
8
9
10
/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return ~x+1;
}

利用 x+~x= -1

-x = ~x+1

isAsciiDigit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 
 * 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 neg=1<<31;
  int l=0x30,r=0x39;
  int r1=x+(~l+1),r2=r+(~x+1);
  return (!(r1&neg))&(!(r2&neg));
}

!(x&(1«31)) : x >= 0

结合上一题

conditional

1
2
3
4
5
6
7
8
9
10
11
12
/* 
 * 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 f=!x;
  f=~f+1;
  return (y&(~f))^(z&f);
}

x=0 f=1-> -1(11111..11)

x=1 f=0 -> 0(00000..00)

然后与运算

isLessOrEqual

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 
 * 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 neg=(1<<31);
  //magical:y-x can pass the test
  int f1=(!(y&neg))&(!(!(x&neg)));//y>=0&&x<=0
  int f2=(!(!(y&neg)))&(!(x&neg));//y<=0&&x>=0
  return (f1&f2)|((!f2)&(!((y+(~x)+1)&neg)|f1));
}

见 isAsciiDigit

logicalNeg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 
 * 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) {
	int a=x|(x>>16);
	int b=a|(a>>8);
	int c=b|(b>>4);
	int d=c|(c>>2);
	int e=d|(d>>1);
  return (e&1)^1;
}

howManyBits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* 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 neg=(1<<31);
  int positive=!(x&neg);//x>=0
  //x = positive ? x : (~x)   -> (-x-1)
  int f0 = ~(!positive)+1;
  int x0 = ((x&(~f0))^(((~x))&f0));
  int cnt=0;
  int ans;
  //int eqneg;
  int eqzero;
  int eqn1;
  int tmp;
  //16
  //cnt= x>=v ? cnt:cnt+16
  int v=1<<cnt+16;
  int fl=!((x0+(~v)+1)&neg);
  f0 = ~(!fl)+1;
  cnt = cnt+(16&(~f0));

  //8
  v=1<<cnt+8;
  fl=!((x0+(~v)+1)&neg);
  f0 = ~(!fl)+1;
  cnt = cnt+(8&(~f0));
  //4
  v=1<<cnt+4;
  fl=!((x0+(~v)+1)&neg);
  f0 = ~(!fl)+1;
  cnt = cnt+(4&(~f0));
  //2
  v=1<<cnt+2;
  fl=!((x0+(~v)+1)&neg);
  f0 = ~(!fl)+1;
  cnt = cnt+(2&(~f0));
  //1
  v=1<<cnt+1;
  fl=!((x0+(~v)+1)&neg);
  f0 = ~(!fl)+1;
  cnt = cnt+(1&(~f0));

  ans=cnt+2;
  //ans=eqneg?32:ans
  // eqneg=!(x^neg);
  // f0 = ~(!eqneg)+1;
  // ans = ((32&(~f0))^(ans&f0));
  //ans=eqzero?1:ans
  eqzero=(!x);
  //f0 = ~(!eqzero)+1;
  //ans = ((1&(~f0))^(ans&f0));
  // ans=eqn1?1:ans
  eqn1=!(x^(~0));
  //f0 = ~(!eqn1)+1;
  //ans = ((1&(~f0))^(ans&f0));

  tmp=eqzero|eqn1;
  f0 = ~(!tmp)+1;
  ans = ((1&(~f0))^(ans&f0));
  return ans;
}

这个有点难,我写了一晚上

思路 :$w+1$ 位补码可以表示的范围是$[-2^w, 2^w-1]$

先考虑 $x>0$ , 需要求出 $w$ 使得 $2^w \leqslant x \leqslant 2^{w+1} -1$

用类似二进制位的想法: 设置一个累加器 cnt,依次尝试 v=16, 8, 4, 2, 1, 如果 x>= 1«v+cnt ,就把 cnt 加上 v

如果 $x<0$ , 我们希望 $2^w \leqslant -x-1 \leqslant 2^{w+1} -1 $ ,这样才有

$-2^{w+1} \leqslant x \leqslant -2^{w} -1$

实现就使用 isLessOrEqual 和 conditional 的技巧就好了

floatScale2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* 
 * 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 e=0;
  int frac=0;
  int i;
  for(i=30;i>=23;i--){
    e<<=1;
    if(uf&(1<<i))e++;
  }
  for(i=22;i>=0;i--){
    frac<<=1;
    if(uf&(1<<i))frac++;
  }
  if(e==255)return uf;
  if(e==0){
    uf=uf^frac;
    frac<<=1;
    uf=uf^frac;
  }
  else {
    uf=uf^(e<<23);
    e++;
    if(e==255)uf=uf^frac;
    uf=uf^(e<<23);
  }
  return uf;
}

比较容易,按照浮点数定义做就可以了

注意非规格化的数转换成规格化的数是很自然的,进位的1刚刚好成为e=1,同时f最高位的1被减掉

floatFloat2Int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* 
 * 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 s=(uf&(1<<31));
  int e=0;
  int frac=0;
  int bias=(1<<7)-1;
  int i;
  int exp;
  int r;
  for(i=30;i>=23;i--){
    e<<=1;
    if(uf&(1<<i))e++;
  }
  for(i=22;i>=0;i--){
    frac<<=1;
    if(uf&(1<<i))frac++;
  }
  exp=e-bias;
  if(exp<0)return 0;
  if(exp>=31)return 0x80000000u;
  r=exp-22;
  frac=frac+(1<<22);
  if(r>=0)frac<<=r;
  else frac>>=-r;
  return s?-frac:frac;
} 

比较容易

####

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 
 * 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 e;
  int bias=(1<<7)-1;
  if(x<-149)return 0;
  if(x<=-127)return 1<<(149+x);
  if(x>=128)return (255<<23);
  e=x+bias;
  return e<<23;
}

容易,但气人的是他一直超时,然后发现是时限太小了