scau CSAPP datalab1

1.用~和&运算实现异或(^)操作

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

2.求二进制补码最小值

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */ 

int tmin(void) {

  return 1<<31;

}

3.判断一个数是否为补码表示的最大值

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */ 

方法一:

补码表示的最大值为:0x 7fff ffff,其用二进制表示就是0111 1111 .... 1111

我们发现,当0x 7fff ffff加1就变成了tmin,也就是1000 0000 .... 0000

那么,把tmin减1就可以得到这个补码表示的最大值了,由于不能用减号,我们可以加-1,而-1可以写成~0x1+1

int isTmax(int x) {
  int ans=0x1<<31;
  int max=ans+(~0x1+1);
  return !(max-x);
}

方法二:

以四位为例,则最大值为x=0111,我们将x+1后再取反,又得到了x。

不信你看,x+1=1000,~(x+1)=0111,因此我们用异或操作来判断它是不是最大值->~(x+1)^x。

不过,这种方法有个特例。当x=-1时,也就是x=1111,x+1=0000(发生了溢出),~(x+1)=1111,

~(x+1)^x =1111,所以要加一个判断条件,判断它是不是-1

int isTmax(int x) {
  return !(~(x+1)&x) && !!(x+1);
}

4.判断是否所有的奇数位的数字都为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
 */

构造所有奇数位为1的数——0x AAAA AAAA(也就是1010 1010 1010 .... 1010),注意,最右边的一位是第0位哦~

然后我们将x与0x AAAA AAAA做&运算,这可以只保留x的奇数位,再判断其与0x AAAA AAAA是否相等即可,若相等则得0,!0=1;若不相等则得1,!1=0

int allOddBits(int x) {
  int a=0xAA<<8;
  int b=0xAA<<16;
  int c=0xAA<<24;
  int d=a|b|c;
  return !((x&d)^d);
}

5.不用"-",求-x

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */

x+(-x)=0,而x+(~x)=-1,可得(-x)= (~x)+1 

int negate(int x) {
  return ~x+1;
}

6.计算输入值是否为0-9的ASCII值

/* 
 * 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
 */

 

其实我觉得吧,不会做题主要是没有耐心看题目,现在重新回头看看这些题,倒也没有想象中的那么难了。

这道题其实就是让我们判断输入值是否在[0x30,0x39]之间

0x30的位级表示为0011 0000,0x39的位级表示为0011 1001

对于输入值x,我们要先满足x<<4==3,也就是得到x的前四位,前四位要等于3,然后后四位在0-9之间就好了。

首先,我们可以用x & 0xF来保留x的后四位(&运算——与1相与是本身,与0相与是0)

7.使用位级运算实现C语言中的 x?y:z三目运算符

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */

好的,什么是三目运算符呢?我来简单说一下。

就是可以把它看成一个if-else语句,如果满足条件x,则执行y,否则执行z

这道题就可以看成if(x!=0) return y;  else return z;

int conditional(int x, int y, int z) {
  x = !!x;
  x = ~x+1;
  return (x&y)|(~x&z);
}

我们需要寻找一种方法,当x!=0的时候让x变成0x FFFF FFFF

1取反后加1就是0x FFFF FFFF了,那么怎样得到1呢?就用两个非运算就可以了。当x!=0时,第一次非运算得到0,再进行一次非运算就可以得到1了。

若x!=0,则x经过一系列运算变成了0x FFFF FFFF,再和y进行与运算就可以保留y的值了;把x取反,变成了0x 0000 0000,与z进行与运算还是0

若x==0,则x经过一系列运算变成了0x 0000 0000,与y进行与运算变成0;取反后成为0x FFFF FFFF,和z进行与运算得z的值

完蛋,这道题把我也绕晕了 

希望有朋友可以教教我TUT

8.使用位级运算实现<=;如果x<=y,则返回1;否则返回0

/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */

判断x<=y有两种方法,一个是x和y的符号相同,且y-x>=0;一个是x和y的符号不同,但x<0

int isLessOrEqual(int x, int y) {
  int negX=~x+1;//-x
  int addX=negX+y;//y-x
  int checkSign = addX>>31&1; //y-x的符号
  int leftBit = 1<<31;//最大位为1的32位有符号数
  int xLeft = x&leftBit;//x的符号
  int yLeft = y&leftBit;//y的符号
  int bitXor = xLeft ^ yLeft;//x和y符号相同标志位,相同为0不同为1
  bitXor = (bitXor>>31)&1;//符号相同标志位格式化为0或1
  return ((!bitXor)&(!checkSign))|(bitXor&(xLeft>>31));
  //返回1有两种情况:符号相同标志位为0(相同)位与y-x 的符号为0(y-x>=0)结果为1;符号相同标志位为1(不同)位与x的符号位为1(x<0)
}

9. 使用位级运算求逻辑非 !

/* 
 * 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 
 */

我们知道-x=(~x)+1,当x>0时,((~x)+1)>>31得1;当x<=0时,((~x)+1)>>31得0。所以我们还要处理x=0和x<0的情况。

我们可以将x和((~x)+1)进行或运算再右移31位,如果(x | (~x)+1)>>31为0,则说明x等于0;如果(x | (~x)+1)>>31为1,则说明x!=0。

int logicalNeg(int x) {
  return ((x|(~x)+1)>>31)+1;
}

10. “一个数用补码表示最少需要几位?”

/* 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 y=~x;
    int tmp1=!((1<<31)&x);
    int tmp2=!((1<<31)&y);
    tmp1=~tmp1+1;
    tmp2=~tmp2+1;
 
    int tmp=(tmp1&x)+(tmp2&y);
    
    tmp=tmp|tmp>>1;
    tmp=tmp|tmp>>2;
    tmp=tmp|tmp>>4;
    tmp=tmp|tmp>>8;
    tmp=tmp|tmp>>16;
    int mask=1;
    mask=(mask<<8)|1;
    mask=(mask<<8)|1;
    mask=(mask<<8)|1;  
    int sum=0;
    sum+=tmp&mask;
    sum+=(tmp>>1)&mask;
    sum+=(tmp>>2)&mask;
    sum+=(tmp>>3)&mask;
    sum+=(tmp>>4)&mask;
    sum+=(tmp>>5)&mask;
    sum+=(tmp>>6)&mask;
    sum+=(tmp>>7)&mask;
    return ((sum&0xff)+((sum>>8)&0xff)+((sum>>16)&0xff)+((sum>>24)&0xff))+1;
}

 11.求2*一个浮点数

/* 
 * 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 sign = uf & 0x80000000;
  unsigned frac = uf & 0x7fffff;
  if(exp ^ 0x7f800000){//exp!=255
     if(!exp){//exp==0
      	frac <<= 1;//此时为非规格化数,尾数无隐含常数1,直接左移1位即可
     }
     else{//0<exp<255
      	exp += 0x800000;//乘2
      	if((exp ^ 0x7f800000)==0){//判断乘2以后是否溢出      	
	  frac=0;//输出INF
      	} 
     }
  }
  return sign | exp | frac;
}

 12.将浮点数转化为整数

/* 
 * 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 INF = 0x80000000;
  //提取符号位
  int s = (uf >>31) & 0x1;
  //提取阶码
  int E = uf >> 23 & 0xff;
  //提取阶数
  int e = E -127;
  if (uf == 0) return 0; 
  //因为输入是规格化浮点数,转化为整数时第23位需要为1
  uf &= 0x00ffffff;
  uf |= 0x00800000; 
  //浮点数中0~22位的数字逻辑上位小数,当看作整数时相当于乘以了2^23
  //阶码为255或阶数大于等于32时,视为溢出,输出INF.因为int为32bit,超出即溢出,且考虑1bit符号位
  if ((uf & 0x7f80000) == 0x7f80000 || e>= 32) return INF;
  if (e<0) return 0;//若为小数,返回零
  //无符号数的移位运算都是逻辑移位 
  if (e <= 23) uf >>= 23 - e;//因为浮点数尾数宽度为23bit,位数小于等于23,尾数位右移.这是一种舍入方式
  else uf <<= e-23;//位数大于23,尾数左移
 
  //当符号位为负数,uf要取值为它的相反数
  if(s) uf = ~uf + 1;
  return uf; 
}

 

13.求2.0^x

/* 
 * 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 = 0xff << 23;
  int INF = 0x7f800000;
  int exp = x + 127 ;
  //溢出
  if(exp >= 255) return INF;
  //为小数时
  if(exp <= 0) return 0;
 
  return exp<<23;
}

太痛苦了!真的!后面的三个题等我缓过来再写吧……

然后,这个答案吧不完全对,有很多小细节我还没来得及一个一个改,还是等我缓过来再写吧……

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值