关于DataLab的准备与解题~

目录

实验准备

一些关于位操作

常见的二进制位操作

关于掩码

一些关于浮点数

题目题解

bitXor(x,y)

tmin()

isTmax(x)

allOddBits(x)

negate(x)

isAsciiDigit(x)

conditional(x, y, z)

isLessOrEqual(x,y)

logicalNeg(x)

howManyBits(x)

floatScale2(f)

floatFloat2Int(f)

floatPower2(x)

总结


实验准备

一些关于位操作

常见的二进制位操作

关于掩码

掩码是一个位模式,表示从一个字选出的位的集合

位级运算x&0xFF生成一个由x的最低有效字节组成的值,而其他的字节就别置为0

例如:

x = 0xABCDEF89

x&0xFF = 0x00000089

(若我们要获去更高位的字节,可以通过移位和该位级运算)↓

x>>8 & 0xFF = 0x0000EF

x>>16 & 0xFF = 0x00CD

x>>24 & 0xFF = 0xAB

一些关于浮点数

•符号(sign)s决定这数是负数(s=1)还是正数(s=0),而对于数值 0 的符号位解释作为特殊情况处理。

•尾数(signiticand) M是一个二进制小数,它的范围是 1~2-€,或者是 0~1-€。

•阶码(exponent) E的作用是对浮点数加权,这个权重是2的正次幂(可能是负数)。

将浮点数的位表示划分为三个字段,分别对这些值进行编码:

•一个单独的符号位s 直接编码符号s.

•k位的阶码字段exp=e0*...ek-1编码阶码 E。(编码E不是说exp=E)

•n位小数宇段frac=f0*...fn-1编码尾数 M,但是编码出来的值也依赖于阶码宇段的值是否等于 0。

根据exp的值被编码的值可以分为三种不同情况

情况一:规格化的值

•exp的位模式不全为0,也不全为1

•此时E=e-bias(单精度bias=127,双精度bias=1023)

•frac是小数点右边那一串,此时M=1+frac

情况二:非规格化的值

•exp的位模式全为0

•此时E=1-bias

•M=frac

情况三:特殊值(无穷大或NaN)

•exp的位模式全为1

•无穷大frac位模式全为0

•NaN的frac位模式不全为0

例如:

15213(10)= 11101101101101(2)

= 1.1101101101101(2)* 2^ 13 

(把15213转化成规格化浮点表示)

•M=1.1101101101101

•E=13 -> exp = e+127=140 -> exp = 10001100(2)

所以15213(10)的浮点数表示为

题目题解

bitXor(x,y)

只使用两种位运算实现异或操作

int bitXor(int x, int y) {
  return ~(~x&~y)&~(x&y);
}

题解:

列异或真值表,得(x|y)&~(x&y),和答案等价

tmin()

返回二进制最小数

int tmin(void) {
  return 0x1<<31;
}

题解:

int是32位,int_min = 0x80000000等价于答案

isTmax(x)

通过位运算计算是否是补码最大值

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

题解:

如果x是tmax(0111...)则tmin=x+1(1000...),x=x+tmin = 111...1,将按位取反得到x=000...0,但是注意-1(0xFFFFFFFF)也符合该转化,所以要排除,此时tmin=0取反为1,x+!tmin 不等于0则可以排除-x为-1的情况

allOddBits(x)

判断所有奇数位是否都为1

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

题解:

用掩码解决,可以参考上文。0x55二进制表示为(01010101),c << 8的二进制表示为(0101010100000000)第一步c的二进制表示为(0101010101010101)以此类推。。。然后通过掩码得到的c和x做与运算获得x的奇数位,其他位为0,再与c异或若为0则奇数位全为1,所以将结果在进行逻辑取反

negate(x)

不使用 - 操作符,求 -x 值

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

题解:

可以自己举例子-1和1的例子试试~

isAsciiDigit(x)

计算输入值是否是数字 0-9 的 ASCII 值

int isAsciiDigit(int x) {
    int a = !(x >> 4 ^ 0x3);
    int b = !((x & 0xA) ^ 0xA);
    int c = !((x & 0xC) ^ 0xC);
    return a & !(b | c);
}

题解:

只要高四位等于三,低四位在0-9则符合题意,右移四位获得高四位异或0x3取反,因为是0-9则(1001)和(1010)不符合题意,x分别与0xA和0xC做与运算获得他的位,在进行异或取反

conditional(x, y, z)

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

int conditional(int x, int y, int z) {
  x = !!x;//第一步
  x = ~x+1;//第二步
  return (x&y)|(~x&z);
}

题解:

第一二步就是把非0的位表示转化为全0,0的位表示为全0.如果x为非0经过第一步其位表示位(000..01),再经过第二步转化为(111...11),如果x为0经过第二步(1111...1+1 -> 100..00)最高位舍去,位表示全为0

isLessOrEqual(x,y)

使用位级运算符实现<=

int isLessOrEqual(int x, int y) {
    int a = ~x + 1;
    int b = y + a;//获得y-x
    int tmin = 1 << 31;
    int xsign = !!(x & tmin);//取到符号位,在进行!!可以得1或0
    int ysign = !!(y & tmin);
    int zsign = b & tmin;//获得y-x的符号位
    return (!(xsign ^ ysign) & !zsign) | ((xsign ^ ysign) & xsign);
}

题解:

分符号相同与不同,符号为相同时要满足y-x>=0,符号不同时要满足x<0。

logicalNeg(x)

使用位级运算求逻辑非 !

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

题解:

0和最小数的补码是本身,其他数的补码是相反数

howManyBits(x)

一个数用补码表示最少需要几位

int bit16,bit8,bit4,bit2,bit1,bit0;
  int sign=x>>31;
  x = (sign&~x)|(~sign&x);//如果x为正则不变,否则按位取反(这样才能进行下面运算,
                        //利用高位是否存在1,将x进行移位运算

  bit16 = !!(x>>16)<<4;//高十六位是否有1,若存在1则bit16=16 二进制表示(10000)
  x = x>>bit16;//如果有(至少需要16位),则将x右移16位
  bit8 = !!(x>>8)<<3;//剩余16位的高8位是否有1,若存在1则bit8=8 二进制表示(1000)
  x = x>>bit8;//如果有(至少需要16+8=24位),则右移8位
  bit4 = !!(x>>4)<<2;//同理
  x = x>>bit4;
  bit2 = !!(x>>2)<<1;
  x = x>>bit2;
  bit1 = !!(x>>1);
  x = x>>bit1;
  bit0 = x;
  return bit16+bit8+bit4+bit2+bit1+bit0+1;//+1表示加上符号位

题解:

正数在计算机中以原码存储,负数以补码存储,则正数的求法是找到最高位1存在位置加符号位,负数的求法本来是找到最高位0存在位置加符号位

floatScale2(f)

求2乘一个浮点数

unsigned floatScale2(unsigned uf) {
  unsigned exp=(uf>>23)& 0xff;//先右移23位再取8位获得exp位模式
  unsigned frac = uf & 0x7fffff;//取23位获得frac位模式
  unsigned ans;
  if (exp==0xff)//特殊情况(无穷大或NaN)
    ans=uf;
  else if(exp)//规格化exp位模式不全为0,2的指数E=exp-bias,所以exp++相当于*2
    exp++;
  else//非规格化exp位模式全为0,E=1-bias,M=frac 根据浮点数表示M*2相当于frac<<1
    frac<<=1;
  ans= (uf&0x80000000) | (exp<<23) | frac;
  return ans;
}

题解:

先获得exp和frac的位模式,对三种情况进行分析,然后和0x80000000做与运算获得符号位,将exp左移23位(ek-1,ek-2,...,e0,000...0),再将三者相或,位为1的将会保留,从而得到浮点数的位表示

floatFloat2Int(f)

将浮点数转换为整数

int floatFloat2Int(unsigned uf) {
  unsigned s=uf>>31;
  unsigned exp = (uf>>23) & 0xff;
  unsigned frac = uf & 0x7fffff;
  int E = exp-127;
  if(exp == 0 && frac == 0)//0的情况
    return 0;
  if(exp == 0xff){//特殊情况
      return 1<<31;
  }
  if(exp == 0){//非规格化,M<1,E=1-127=-126,值很小
      return 0;
  }
//规格化
  frac = frac|(1<<23);//此时frac等于M
  if(E>31)//溢出
    return 1<<31;
  else if(E<0){
      return 0;//1<M<2,E最小为1/2,所以值小于1
  }
  if(E>23){
      frac<<=(E-23);//如果E大于23,frac可以左移则右边有更多的0位
  }else{
      frac>>=(23-E);//如果E小于23,则要右移,否则frac会多出位
  }
  if(s)
    return ~frac+1;
  else
    return frac;
    

}

题解:

规格化时,frac位数是23,E很大时,frac的位都能保留,还能多给0位(不变),所以将frac左移,E小于23时,frac要裁掉后面的无效位,才能满足M*2^E(M=1.xxxx),正数返回frac,负数用补码存储,所以返回frac的补码

floatPower2(x)

求 2.0^x

unsigned floatPower2(int x) {
    if(x<-149){
    return 0;
}else if(x<-126){//非规格
    //E = x = 1-127 = -126
    int move = 23+(x+126);
    return 1<<move;  
}else if(x<127){
    int exp = x+127;//E = exp-127
    return exp<<23;
}else{
    return (0xff)<<23;
}

}

题解:

2.0^x是非负数,所以可以表示为M^2E。找到非规格化和规格化的表示范围。非规格化时,M最小为2^-23(000...001),E=-126,所以非规格化最小是M^2E=2^-149。M最大表示(111...11),E=-126,所以非规格化最大是M^2E=2^-126(取不到)。

规格化时,M最小为1.0,E最小等于1-127 = -126(因为规格化时exp不能全0,最小位表示[00000001])

所以规格化最小是M^2E=2^-126。M尽可能大1.111...1,E最大254-127=127(exp位表示11111110),M最大小于2,所以规格化最大在2^127~2^128.

当范围在非规格化时2.0^x = M*2^E,此时2^E=2*-126所以M需要补充(x+126)需要的位,只要返回M的位模式就是最终答案,frac有23位,令move=23+(x+126)可以得出要移动的位数,最后返回1左移需要移动的位数。

总结

好好理解实验准备,可以画画草稿

要是有错误求求大佬指出,小白发滴第一篇博客嘿嘿嘿!~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值