lab1-解题

 * absVal - absolute value of x
 *   Example: absVal(-1) = 1.
 *   You may assume -TMax <= x <= TMax
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 10
 *   Rating: 4
 */
代码:

int absVal(int x) {
  int a,b;
a=x;
b=x;
a=a>>31;
b=b^a;
b=b+!!a;
return b;

}

解题:这个题意思是让用位运算求出一个数的绝对值,首先普及下负数如何变为整数,方法是:负数的二进制数先取反,然后加一就是它的绝对值了,比如说-5的二进制是1111 1011 取反 0000 0100 然后加一0000 0101,至于为什么要这么做,背过就可以,博主也不知道...如果这个数为正数,a左移了31位,结果就是0,b与0异或还是b,此时下面的!!a也是0,b+0还是b,所以返回的还是正数b,如果此时的b为负数的时候就不同了,先看第三行代码,左移了31位,此时a的值变成了-1,所有位上全是1,此时用原来的数和-1异或一下,相同为0,不用为1,这也就实现了负数取反的操作,由于此时a为-1,进行两次的!,之后便是1,这样得到的数值便是b的绝对值了,整个代码也就完成了求一个数绝对值的功能了.。

/* 
 * 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);
}

解题:这个题意思是表示出两个数的异或。这个代码从右面~(x&y)这个开始讲,这个功能是使同1的为1,其他都为0(都是0为0,不同也为0),取反之后就是将相同且都为1置为0(其中包括同为1,同为0),其他的为1,~(~x&~y)的功能是,不同置为1,相同的且为1的置为1,相同且为0的置为0,这样这两个再与一下,相同为0,不同为1.

/* 
 * byteSwap - swaps the nth byte and the mth byte
 *  Examples: byteSwap(0x12345678, 1, 3) = 0x56341278
 *            byteSwap(0xDEADBEEF, 0, 2) = 0xDEEFBEAD
 *  You may assume that 0 <= n <= 3, 0 <= m <= 3
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 25
 *  Rating: 2
 */
int byteSwap(int x, int n, int m) {
    int a,b,c,p1,p2,p3,p4,p5=0xff;
    b=c=x;
p1=m<<3;
p2=n<<3;
b=b>>p1;
b=b<<p2;
c=c>>p2;
c=c<<p1;
p3=p5<<p1;
p4=p5<<p2;
p5=p3|p4;
a=(b&p4)|(c&p3);
x=((p5|x)&~p5)|a;
return x;
}

解题:这个题是让求转移字节位,我的思路可能会有些麻烦,当时自己也硬凑出来的,大家凑付看吧,首先p1=m<<3和p2=n<<3

,p1,p2存的是移动的字节数,左移3就是乘以n*8或m*8,b=b>>p1和b=b<<p2的意思是将x中的m位字节移到n位上,c=c>>p2和c=c<<p1的意思是将x中的n位字节移到m位上,p3=p5<<p1和p4=p5<<p2是将移动的位上的数置为1,此时a得到的是移动的位置已经移动好,其他位是0,(p5|x)&~p5的意思是让使其他没有动的位不动,而其他动的位置置为0,得到的结果与a或一下,得到结果。


/*
 * oddBits - return word with all odd-numbered bits set to 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 8
 *   Rating: 2
 */
int oddBits(void){
int a=170,b=170;
a=a<<8;
a=a|b;
b=a;
a=a<<16;
a=a|b;
return a;
}

题解:这个题的意思是所有的奇数字节置为1,所以说可以设置一个二进制数00000000000000000000000010101010作为基数进行左移,就可以达到目的,首先a=a<<8,a左移8位,得到的数可以和原来的数字或一下,得到的数字00000000000000001010101010101010,这样就可以在这个的基础上进行左移16位并且把原来移动的数进行保存下,左移16位后的数字再和刚才左移8位后或的数再或一下,就可以得到10101010101010101010101010101010,达到目标!

/*
 * isLess - if x < y  then return 1, else return 0
 *   Example: isLess(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLess(int x, int y) {
  int a1,a2,b1,b2,b3;
a1=(x>>31)&0x1;
a2=(y>>31)&0x1;
b1=a1&~a2;
b2=((~x+y)>>31)&0x1;
b3=~a1&a2;
return (b1|!b2)&!b3;
}

题解:这个题分三种情况:

1.x>0,y>0 x<0,y<0 

2.x>0,y<0

3.x<0,y>0

首先a1和a2得到的是1或者是0,这个操作是得到这两个数是负数还是正数,b1的操作主要是对于第2,3种情况来说明的,对于第2和3种情况是很明确知道他俩的大小了,比如说第二种,x>y,这个时候要返回一个0,而此时a1=0,a2=1,所以说只要将a2取反就可以了,这样两个都是0,只要&(与)一下就可以了,第3种是同样的道理,而第一种情况不由b1的表达式所限定,应为两个异号与一下是0,所以说对于第一种情况主要受b2表达式所决定,b2我也是没有搞清楚,但是主要功能就是((~x+y)>>31)&x1取代了没有减号比较两个数大小的功能,如果说x>=y,此时他的值就是1,x<y,此时他的值是0,所以要再加一个!,此时才是我们想要的答案,至于b3的功能呢是在2,3种情况下,由于b2也参与了运算,所以对结果也会造成影响,所以说要加一个b3来限制下,而!b3在第一种情况下恒为1,不会有影响,所以说只会对2,3种情况造成影响,对于第二种,!b3的值为0,第三种,!b3的值为1,其实b3存在的意义主要是针对第2,3种情况下,b2会对结果影响,所以说对结果进行限制下,有的同学会发现其实b1根本没有起到什么作用,只需要!b2&!b3就可以完成任务了,其实是不对的,比如说给你个0x80000000和0x7fffffff,其实就一目了然了,这时候的!b2的结果是0,很明显他对结果产生了限制了。

/* 
 * float_abs - Return bit-level equivalent of absolute value of 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 representations of
 *   single-precision floating point values.
 *   When argument is NaN, return argument..
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 10
 *   Rating: 2
 */
unsigned float_abs(unsigned uf) {
unsigned a=0x7f800000;
unsigned b=0x7fffffff;
unsigned c=uf&b;
if(c>a)
return uf;
else
return c;
}

题解:这个题float存储的问题,一共32位,从左往右,第一位表示正负,后面8个表示指数位,也就是移动的位数,这个移动是转换成二进制后再移动的,后面23个表示移动后的小数位,这里强调下,对于flaot存储正数和负数只是首位不同,其他都相同,下面解释下代码。

a是指数位位置满了,说明移动的位数最大, 表示这个数已经是极大了,所以说超过这个界限就只能返回他的原数了,一开始将原数和b与一下是取这个数的绝对值,下面就没有什么可说的了。

/* 
 * isEqual - return 1 if x == y, and 0 otherwise 
 *   Examples: isEqual(5,5) = 1, isEqual(4,5) = 0
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int isEqual(int x, int y) {
  return !(x^y);
}

题解:这个题意思是相同返回1,不同返回0,其实这个题将两个数异或一下就可以了,如果相同的话,全为0,此时再用一下“!”,转为1,如果不同的话,肯定至少有一位是1,这样用下“!”,这样数变为0,达到目的。

/* 
 * float_twice - 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 float_twice(unsigned uf) {
  unsigned f=uf;
if((f&0x7f800000)==0)
{
f=((f&0x007fffff)<<1)|(f&0x80000000);
}
else if((f&0x7f800000)!=0x7f800000)
f=f+0x00800000;
return f;
}

题解:这个题分情况讨论

1.指数位置全为0

2.指数位置不全为1

3.指数位置全为1

首先先针对第一种情况,这种情况只要左移1位就可以了,剩下只需要考虑它的正负号,再或或者是与上一个首位就可以了。

接下来第二种情况可以讨论指数位置是不是满了,这样先把它和指数位全满的与一下,再看一看它和全满的是不是相等,不相等,说明他还没有满了,这时候只需要加上一个最低的指数位置就可以了

其他情况就是全为1,返回原值即可

/*
 * satAdd - adds two numbers but when positive overflow occurs, returns
 *          maximum possible value, and when negative overflow occurs,
 *          it returns minimum positive value.
 *   Examples: satAdd(0x40000000,0x40000000) = 0x7fffffff
 *             satAdd(0x80000000,0xffffffff) = 0x80000000
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 30
 *   Rating: 4
 */
int satAdd(int x, int y) {
  int sum=x+y;
int over=((x^sum)&(y^sum))>>31;
return (sum >> (over & 31))+(over << 31);
}

题解:

溢出分为两种情况:负加负得正      正加正得负

sum里面存x+y的值,

核心代码:over里面其实主要看第一位,如果是sum溢出了,无论溢出是哪种情况结果都是x^sum为1,y^sum为1,这样只要是溢出over就是1,over&31得到还是31,如果是负负溢出的话,sum最高位是0,右移变成32个0,也就是0x0再加上over左移31位就是0x80000000,加上就是0x80000000;如果是正正溢出的话,sum最高为是1,右移31位变成0xffffffff,这样加上0x80000000,最高为溢出就是得到0x7fffffff,如果不溢出的话,over是0,得到数还是sum原数。

/*
 * bitCount - returns count of number of 1's in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
 */
int bitCount(int x) {
int a1=0x55;
int a2=0x33;
int a3=0x0f;
int a4=0xff;
int a5;
a5=a4;
a1=(a1<<8)|a1;
a1=(a1<<16)|a1;
a2=(a2<<8)|a2;
a2=(a2<<16)|a2;
a3=(a3<<8)|a3;
a3=(a3<<16)|a3;
a4=(a4<<16)|a4;
a5=(a5<<8)|a5;
x=(x&a1)+((x>>1)&a1);
x=(x&a2)+((x>>2)&a2);
x=(x&a3)+((x>>4)&a3);
x=(x&a4)+((x>>8)&a4);
x=(x&a5)+((x>>16)&a5);
return x;
}

题解:这道题运用了分治的方法。

这里引用一下大佬写的东西,简单易懂的:http://www.cnblogs.com/cdp1591652208/p/7697753.html

其实这道题没有这么复杂,主要表达式其实也就5个,上面的a1到a5是没办法,a1不让直接定义成0x55555555,所以通过移位来实现了,下面写一下自己的见解,可能没有大佬思路那么清楚,大家凑合看一下。

首先说一下

a1=0x55555555         二进制:11111111111111111111111111111111

a2=0x33333333         二进制:00110011001100110011001100110011

a3=0x0f0f0f0f             二进制:00001111000011110000111100001111

a4=0x00ff00ff             二进制:00000000111111110000000011111111

a5=0x0000ffff             二进制:00000000000000001111111111111111

这里举一个例子,给一个二进制数:10001000100010001000100010001000

1.首先第一个x&a1的意思是让保留x的偶数位0,2,4,6.....,x>>1&a1的意思是保留x的奇数位,然后对应位置相加,这样不会溢出,因为最高位置是奇数所以不会两个相加溢出的现象,这样可以分成短暂的两位的存储空间,

00000000 00000000 00000000 00000000

01000100 01000100 01000100 01000100

这样相邻的两位相加,00+01=01,00+00=00,00+01=01 ......

这样得到一个相邻数相加得到二进制:01000100 01000100 01000100 01000100

2.第二个x&a2的意思是因为上面第一步已经将两个相邻的位置加在一起了,所以说现在从相邻两个为一组,将现在的二进制数分为16组0,1为偶数组,2,3为奇数组....,这样x&a2的解释还是和上面的一样,只是变成了组的形式,保留偶数组,x>>2&a2保留x的奇数组,然后对应的相加,这样可以分为短暂四位的存储空间

偶数组得到:00000000 00000000 00000000 00000000

奇数组得到:00010001 00010001 00010001 00010001

相加得到:00010001 00010001 00010001 00010001

3.第三个x&a3的意思是因为2个为一组的相邻位置已经加在一起了,所以说现在相邻的4位作为一个基本的单元为一组,现在便可以将二进制数分为8组0,1,2,3为偶数组,4,5,6,7为奇数组....,这样x&a3的解释还是和上面的一样,只是变成了组的形式,保留偶数组,x>>4&a3保留x的奇数组,然后对应的相加,这样可以分为短暂八位的存储空间

偶数组得到:00000001 00000001 00000001 00000001

奇数组得到:00000001 00000001 00000001 00000001

相加得到:00000010 00000010 00000010 00000010

4.第四个x&a4的意思是因为4个为一组的相邻位置已经加在一起了,所以说现在相邻的8位作为一个基本的单元为一组,现在便可以将二进制数分为4组,0,1,2,3,4,5,6,7为偶数组,8,9,10,11,12,13,14,15为奇数组...,这样x&a4的解释还是和上面的一样,只是变成了组的形式,保留偶数组,x>>8&a4保留x的奇数组,然后对应的相加,这样可以分为短暂八位的存储空间

偶数组得到:00000000 00000010 00000000 00000010

奇数组得到:00000000 00000010 00000000 00000010

相加得到:00000000 00000100 00000000 00000100

5.第五个x&a5的意思是因为8个为一组的相邻位置已经加在一起了,所以说现在相邻的16位作为一个基本的单元为一组,现在便可以将二进制数分为4组,0,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为奇数组...,这样x&a5的解释还是和上面的一样,只是变成了组的形式,保留偶数组,x>>16&a5保留x的奇数组,然后对应的相加,这样可以分为短暂十六位的存储空间

偶数组得到:00000000 00000000 00000000 00000100

奇数组得到:00000000 00000000 00000000 00000100

相加得到:00000000 00000000 00000000 00001000

所以说最后结果是8!!!

结束!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值