启用方式
将压缩包解压,使用命令行进入目录,输入make
,然后输入./btest
即可开始测试
int注意事项
Each "Expr" is an expression using ONLY the following:
- Integer constants 0 through 255 (0xFF), inclusive. You are
not allowed to use big constants such as 0xffffffff.- Function arguments and local variables (no global variables).
- Unary integer operations ! ~
- 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:
- Use any control constructs such as if, do, while, for, switch, etc.
- Define or use any macros.
- Define any additional functions in this file.
- Call any functions.
- Use any other operations, such as &&, ||, -, or ?:
- Use any form of casting.
- Use any data type other than int. This implies that you
cannot use arrays, structs, or unions.You may assume that your machine:
- Uses 2s complement, 32-bit representations of integers.
- Performs right shifts arithmetically.
- Has unpredictable behavior when shifting if the shift amount
is less than 0 or greater than 31.
简单来说,就是不能用控制语句,函数,宏
运算符只能用+以及一些位运算,逻辑符号只能用!(具体看每道题目的要求)
bitXor
简单的异或
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
*/
int bitXor(int x, int y) {
/*
0 1 = 1,其余为0
a&~b = 1时,当且进当 a = 1且b = 0
b&~a = 1时,当且进当 b = 1且a = 0
二者或在一起就是同或了
而 a | b = ~~(a|b) = ~(~a&~b)
*/
return ~(~(x&~y)&~(y&~x));
}
tmin
只需要记住补码的范围是-2n-1~2n-1-1即可
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
int t = 1<<31;
return t;
}
isTmax
最大值即2n-1-1,或者说是01111..1
这里方法挺多的,就只用一个简单的表示把
/*
* 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) {
/*
当且仅当x为最大数时,x+1 = 10000..00,此时按位加1000.0000等于0
*/
int t = ~x + ~x;
t = t|!(x+1);
return !t;
}
allOddBits
构造出一个奇数位上全为1,其他位置全为0的数,然后将这个数与检测数进行&
,如果待检测的数有若干个奇数位为0,则结果将在构造的数的基础上,损失一些1,在利用当且仅当a=b时,有a^b=0的性质,来检验计算出来的值是否有损失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) {
int a = 0xa;
a = (a<< 4) + a;
a = (a<<8) + a;
a = (a <<16) + a;
return !((x &a)^a);
}
negate
究极基础题,但我还是忍不住提一嘴补码的一些东西.
由于计算机存储有限,所以整型数据有一种叫做“模”的东西限制了数据的范围,将模记作mod
则对于满足x = y + mod*a(0<=y<mod)的x和y来说,在计算机存储的内容均为y,这也就意味着,在整形数据计算过程中,任意的加入模进行加减运算其实都是不影响结果的。
因此,我们考虑两个数据a,b的做差,即 a - b的计算,我们可以在计算前,在中间加入一个mod,即
a-b = a + (mod - b),由于计算过程是在计算机中进行的整形计算,所以b肯定是要小于mod的,故(mod-b)必然为正数,这样就可以将减法运算转化为加法运算。
同时,我们知道计算机的数据全是由01,也就是二进制表示的,因此我们可以将mod = 1 000...000写成,1111...111+1的形式
而1111...111 - b,左边的每一位都有1,而b用二进制表示为01串,每一位都可以和左边的对应位置的位对应上,而1-0=1,1-1=0,所以结果相当于b上的每一位都进行了取反。
别忘了前面还漏掉了一个1,所以负数也就是(0-b) = (mod-b) = ~b+1
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
isAsciiDigit
这道题我主要是将0x3m(0<=m<9)拆分成了0003和m分别检验
首先是将数据右移,将m占用的位移出去,就可以不考虑m的影响。然后就像是上面提到的结论一样,只有当这个数是0x3时,他异或上0x3才为0.
接着就是检验m了,考虑到需要的范围时0~9,而在这个范围内的数字,在加上6以后最大为0xf,是不会产生进位的,而0xa ~ 0xf得数据却会产生进位,因此将数据加上一个6,再用上面的方式检验0x3是否改变即可
/*
* 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) {
/*
当且仅当俩个数一模一样的时候,按位加才为0,所以先检测前面是否为3,在然后排除0x3a等情况,加上6之后,a以及之后的数会产生进位
*/
// return !((x^0x30)>>4)|(((x+0x6)^0x30)>>4); 括号没打好
int t1 = (x>>4)^3;
int t2 = ((x+6)>>4)^3;
return !(t1|t2);
}
/*
conditional
这个主要是利用了0和111111(即-1)互相取反的关系,而任何数&0则会将数据完全清空,而&11111则会保持不变,对俩个数分别&上0和111再|在一起,就可以实现保留一个数据而清空一个数据,而任何数|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) {
/*
将0转化为0,非0值转化为1111111
*/
int flag = !x;
flag = flag + ~0;
return (y&flag )| (~flag&z);
}
isLessOrEqual
这个还蛮麻烦的
首先就是将x,y的符号给提取出来。(这里姑且将0看作正数)
然后可以分为3种情况,分别将结果作为条件码保存
1.x正,y负,必然是x大,返回0
2.x负,y正,x小,返回1
3.x,y符号相同,直接采用做差的方式,判断结果的符号位是正是负来判断大小关系,由于x,y同号,所以作差时也就不需要考虑溢出问题。
最后将这三个条件码合理的用逻辑符号组合在一起就行
值得一提的是,虽然题目不让用 &&和||,但是由于前面三个条件码只会为0或者1,所以采用&和|其实取到的效果是一样的。
/*
* 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) {
/*
当x > 0的,y小于0,返回false,x<0,y大于0,返回true,t1则是根据符号位来判断是否是
*/
int sigx = x>>31,sigy = y>>31;
int t1 = sigx&(!sigy);
int t2 = sigy&(!sigx);
int t3 = y + ~x + 1;
t2 = !t2;
t3 = t3 >>31;
t3 = !t3;
return t1|(t2&t3);
}
logicalNeg
这个的话呢还是困扰了我蛮久的
方法一:自己想的
判断一个数是不是非0的方法很简单,直接给他加一个离模差1的数,看他溢不溢出就完事了,但是C语言的溢出了的话,我也看不到条件码,就不能采取这么直接的方法了。
于是可以考虑人为的将数据缩短一点,即将数据的后16位|上前16位,因为数据非0的话,那么前面和后面16位至少有一个处非全0,二者|在一起得到的16位肯定是非0的,同时我们将这个得到的数据除了得到的16位,前面的16位清空。
那么,只要原本的数非0,我们就可以得到一个非0的16位的串。
这时候,我们以216次方为模,给这个串加上一个216-1,若数据非0,那么第16位上肯定有一个溢出的1,否者仍然为0.
方法二:知乎上看来的
在补码的范围中,除去0和最小的数比较特殊,每一个数都有对应的相反数,通过取反加一可以得到一个符号相反的相反数,二者的符号或在一起便是1,而0通过取反加一得到的仍然为0,或在一起为0,而最小数取反加一得到的也是自己,但是符号位都是1,或在一起结果也是1.
也就是说,非0数与自己的相反数(或者说取反加一得到的数)|在一起,符号位均为1,而0通过这样的操作符号位为0.
通过以上俩种操作,我们就可以区分0和非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) {
/*
*/
int y =x>>16;
int n = ((1<<16)+ ~1 + 1);
y = y&n;
x = x & n;
x = x|y;
x = x + n;
x = x>> 16;
x = 2 + ~x ;
return x;
}
howManyBits
想要用一个最短的串来表示一个数
首先我们肯定需要一个0或者1来表示符号
然后对于正数而言,除了符号位的0以外的前导0都是没有什么特别实质的意义的,因此都可以删去,也就是说仅需要保留从左往右,第一个1前面的0作为符号位即可。
为了避免分类,同时注意到,正负数情况时的高度相反性,可以对负数直接取反,这样就可以直接进行正数的操作。
到这一步,目标就很明确了,就是求出数中从左往右第一个1所在的位置,再加上1即可。
这里主要是采取了二分的方法,将左半边的数单独取出来,如果非0的话,说明左边一定有1,所以第一个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
* -5 = 1011
* howManyBits(0) = 1
* 0 = 0
* howManyBits(-1) = 1
* -1 = 111111 = 1
* howManyBits(0x80000000) = 32
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int howManyBits(int x) {
/*
从左往右,找到第一个不等于符号位的,位数+1
现将负的转化为正的
然后就是找到第一个1的位置
*/
int mask = x>>31;
x = x^mask;
int a = 1;
int t = !(x>>16);
t = t + ~1+1;
t = 16&t;
a = t+a;
x = x>>t;
// printf("%x\n",x);
t = !(x>>8);
t = t + ~1+1;
t = 8&t;
a = t+a;
x = x>>t;
// printf("%x\n",x);
t = !(x>>4);
t = t + ~1+1;
t = 4&t;
a = t+a;
x = x>>t;
// printf("%x\n",x);
t = !(x>>2);
t = t + ~1+1;
t = 2&t;
a = t+a;
x = x>>t;
// printf("%x\n",x);
t = !(x>>1);
t = t + ~1+1;
t = 1&t;
a = t+a;
x = x>>t;
// printf("%x\n",x);
t = !x;
t = t + ~1+1;
t = 1&t;
a = t+a;
// printf("%x\n",x);
return a;
}
float的注意事项
FLOATING POINT CODING RULES
For the problems that require you to implement floating-point operations,
the coding rules are less strict. You are allowed to use looping and
conditional control. You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants. You can use any arithmetic,
logical, or comparison operations on int or unsigned data.
You are expressly forbidden to:
1. Define or use any macros.
2. Define any additional functions in this file.
3. Call any functions.
4. Use any form of casting.
5. Use any data type other than int or unsigned. This means that you
cannot use arrays, structs, or unions.
6. Use any floating point data types, operations, or constants.
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 operations (integer, logical,
or comparison) that you are allowed to use for your implementation
of the function. The max operator count is checked by dlc.
Note that assignment ('=') is not counted; you may use as many of
these as you want without penalty.operatorsRPRISES:
* 1. Use the dlc compiler to check that your solutions conform
* to the coding rules.
* 2. Use the BDD checker to formally verify that your solutions produce
* the correct answers.
*/
总的来说就是除了浮点数运算,函数,其他都能用
float
主要是不知道为什么,睡不着,才从床上爬起来写的,但是蚊子有点多,浮点数的话,这部分没什么难的,主要还是弄清楚浮点数的结构,以及一些小细节,直接贴一下结果了,就不继续罗里吧嗦了
GTMD蚊子
/*
* 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) {
unsigned int s = uf>>31;
unsigned int e = uf<<1;
e = e >>24;
unsigned int m = uf<<9;
m = m>>9;
if(e==255){
return uf;
}
if(e == 254){
return (s<<31)+(255<<23);
}
if(e>0){
return (s<<31)+((e+1)<<23)+m;
}
return (s<<31)+(m<<1);
}
/*
* 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) {
unsigned int s = uf>>31;
unsigned int e = uf<<1;
e = e >>24;
unsigned int m = uf<<9;
m = m>>9;
// printf("s = %x e = %x,m = %x\n",s,e,m);
if(e<127){
return 0;
}
if(e-127>=31){
return 1<<31;
}
m = (1<<23)+m;
// printf("%x\n",m);
int p = e-127 + 1;
// printf("%d\n",p);
p = 24 - p;
// printf("%d\n",p);
m = m>>p;
// printf("%d\n",m);
m = s?-m:m;
return m;
}
/*
* 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 INF = 255<<23;
if(x>127)return INF;
if(x<-149)return 0;
if(x>-127)return (x+127)<<23;
int t = -126 - x;
t = 23 - t;
t = 1<<t;
return t;
}