前言
本系列文章意在记录答主学习CSAPP Lab的过程,也旨在可以帮助后人一二,欢迎大家指正!
一、 bitXor()
本函数限制只能使用~和&来完成x^y,即异或运算。
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
*/
int bitXor(int x, int y) {
//return ~(~x&~y)&~(x&y);
return ~(~(~x&y)&~(x&~y));
}
其中实现的逻辑比较简单,学习过离散数学的都知道,使用德摩根律即可。
二、tmin()
返回最小的补数,通过这道例题来深入理解补数的定义。
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 1 << 31;
}
三、isTmax()
找出补数形式的最大值
/*
* 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) {
//return x == ~(1 << 31); //illegal operator == <<
return !(x ^ ~(x+1))&!!(x+1); // -1 is a special case / exception
}
思路
我在做的时候,先将其真实值写出来,然后分析其特征。
对于四位数而言0111
就是最大补数,会发现此数+1取反就会变回自身,所以我们只要判断变化后是否与原来相同就好了。
但不能使用==
,那么问题又进展到了如何用位运算来表示==
CSAPP中有一道练习题就是此问,我们观察异或运算就可得知,同位的数相同若则为0 ,所以逻辑运算x == y
可以表示为!(x^y)
,不理解的童鞋可以算一下哦~
但这道题还没完!!!!我们这种思路还有一个小小的bug。。。。
对于-1
即1111
来说,也符合我们上面的做法,所以要在最后的结果中排除此特殊情况。
这边排除的时候有一个小的技巧,用逻辑判断!!
两次非,就可以将-1去除掉啦!
四、allOddBits()
若二进制数字串中奇数位都为1的话,就令其返回1。
/*
* 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) {
//return !(0xAAAAAAAA & x ^ 0xAAAAAAAA); //illegal constant 0xAAAAAAAA
int a = 0xAA;
int b = (a << 8) | a;
int c = (b << 16) | b; // c == 0xAAAAAAAA
return !((c&x) ^ c);
}
思路
题目中给的例子已经有提示了!! A = 1010
这不就是天然的奇数位为1的最好情况吗!
然后我们就可以通过这个天然的标杆来判断了,岂不是很棒!
但因为题目中限制不能直接给常数,所以我们只能通过|
的方式来不断拓展A的长度,形成0xAAAAAAAA
之后我们只要通过c&x
将x中偶数位为1的清洗为0,然后判断其与0xAAAAAAAA
是否相同就好了
五、negate()
返回其相反数
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
这个题目比较简单,就不细说了,只要了解数字几种形式基本转化方式的都知道。
六、 isAsciiDigit()
确定x是否在某一范围内
/*
* 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) { // my operator is very complex my_pos = Max_ops = 15
int x1 = 0x30;
int x2 = 0x39;
int a = x + (~x1+1);
int b = x2 + (~x+1);
int test = 1 << 31;
//return !(test & a) && !(test & b); //illegal operator &&
return !(!!(test & a) + !!(test & b));
}
思路
本题我用了最朴素的想法,通过x与上下限相加减所得的数与零的关系来确定是否在些区间内
通过a & (1 << 31)
来判断正负数。
七、conditional()
模拟实现c语言中的三目表达式 ? :
/*
* 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^0); //logic --> number
x = ~a+1; //a == 1 x = 0xFFFFFFFF a == 0 x = 0x00000000
return (x & y) + ((~x) & z);
}
思路
既然是通过x的值来判断返回y还是z,那就可直接得出 return (x & y) + ((~x) & z);
然后只需通过逻辑表达式与一些小操作将x转换为0xFFFFFFFF
或者0x00000000
即可。
后面的几个函数实现涉及到太多的tricky了,准备暂时先行跳过,先完成最最重要的知识学习!