Datalab做题笔记

Datalab做题笔记

0x1 bitXor

只用~&表示^
分析:(横着的是a,竖着的是b)
XOR

1 0
1 0 1
0 1 0

~A = a&~b

1 0
1 0 0
0 1 0

~B = ~a&b

1 0
1 0 1
0 0 0

A&B

1 0
1 1 0
0 0 1

再对A&B取~得到XOR

XOR = ((a&(~b) ) & ((a) & b) )

0x2 tmin

输出int的最小值
解析: 补码Tmin最高位为1,其他位为0。int有32bit,则Tmin = 1 <<31

0x3 istmax

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

解析:Tmax除了最高位是0,剩下的31bit全为1
操作符可以用 ! 那么想办法把Tmax凑成0就可以了

  1. (Tmax + 1) = (10000.....)
  2. Tmax + Tmin = -1
  3. ~(-1) = 0
  4. 也就是当x = Tmax, ~ ((x + 1) + x) = 0
  5. 主要到对于0xffffffff也成立, 特判即可

整理得到
ans = !((~((x + 1) + (x))) | (!(x + 1)))

0x4 allOddBits

Legal ops: ! ~ & ^ | + << >>
题意:判断奇数比特是否是1
例如 (大端机器)A = 1010(从左向右) 奇数位全是1,题目要求最多12个操作符。所以不能一个个判断。

  • 假如我们已经有了Book = 0xAAAAAAAA

  • 那么y = x&Book,奇数位是1,偶数位全是0。

  • ~Book + y 如果奇数位全是1,那么此时32个比特上全是1。再取反,符合条件的全是0

  • 得出ans = !(Book + x & Book)

0x5 negate

用位运算计算-x
解析: -x = ~x + 1

0x6 isAsciiDigit

判断是否为ASCII数字
解析: 在前一个小问,已经可以做出减法。只要判断是否在0和9之间即可。 注意边界处理
还有一个要注意的点就是,如果用第一个bit判断正负,0的第一位和正数第一位都是0,需要先减去1,这样就可以区分开了。

	int isAsciiDigit(int x)
	{
  		int minusX = (~x) + 1;
  		int m = (minusX + 0x30 -1 ) >> 31; // -
  		int n = (0x39 + minusX ) >> 31;//+
  		return (m)&(!n);
	}

0x7 conditional

return x ? y : z
思路: 如果x非0,那么返回y,否则返回z。
先j = y ^ z, 再XOR得到结果

考虑cnt = !x - 1

x 操作
cnt 0xffffffff 0
y 0 1(需要XOR)
z 1 0
	int conditional(int x, int y, int z)
	{
  		int cnt = !x - 1;
  		return (y ^ z) ^ (y & (~cnt)) ^ (z & (cnt));
	}

0x8 isLessOrEqual

判断是否x小于等于y?

return x <=y
x <= y
y - x >=0

但是int加减可能造成溢出。
进行优化:
如果符号相同,那么正数大于负数。
如果符号相反,那么判断差值。

int isLessOrEqual(int x,int y) 
{
    int signX = x >> 31, signY = y >> 31;
    int conditionOne = (signX & 1) & (!(signY | 0)); 
    int minusX = (~x) + 1;
    int conditionTwo = (y + minusX) >> 31;
    return conditionOne | ( (!((!(signX|0))&(signY&1)))&(!conditionOne) &(!conditionTwo));
}

貌似写的很丑陋,符号用的太多了

0x9 logicalNeg

使用位运算计算x。
解析:也就是符号为全是0,返回值为1。否则为0。注意到负数的首个bit一定为1,正数的相反数首个bit也是1(补码原理)。那么0呢?0再怎么取相反数,首位都是0。嘻嘻
注意,就是int范围并不是对称的,-2147483648取反溢出等于-1

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

0xA howManyBits

题意: 判断一个数字至少用多少bit的补码。
分析: 比如-5,因为$-5 = -2^3 + 2 + 1$可以用补码$(2)1011$一共四位表示。而$9 = 2 ^ 3 + 1$不难发现规律是向下取幂。对于正数,是找最高位的1,对于负数,是找最高位的10再上一位。取反就是01再上一位。
x = x(负数) ? (-x) : x
前面写过三目运算符了。

	x = (~x&(x >> 31) ) | (x&(~(x>>31)))

这样x如果是负数就被取反了。现在我们需要找到最高位的1在哪个地方。

  x = x | (x >>2);
  x = x | (x >>4);
  x = x | (x >>8);
  x = x | (x >>16);

因为这样最高位的1一定能够填充右边的所有bit,所以再统计有多少个1。最后cnt+1就行辣。
这道题最多可以用90个操作符,我们当然可以一个个bit统计,但是这样太猪鼻了。
让我们想想,如果前16位有至少一个1,那么至少有16个1;

	if(前16位有1)
		f(统计前16位1的个数)
	else
		f(统计后16位1的个数)

!!(x>>16 & (-1))如果结果是1,则前16位为1。
x = x >> (16 & -flag)表示右移选择
举个例子,当最后还剩2位时,只有11,10,00这三种情况。
前两种右移1位,得到1,后一种不用右移,还是0。所以最后还要加右移完的x。

int howManyBits(int x)
{
  x = (~x&(x >> 31) ) | (x&(~(x>>31)));
  int cnt16,cnt8,cnt4,cnt2,cnt1;
  cnt16 = (!!((x>>16)&(-1))) << 4;
  x = x >> cnt16;//remain 16bit
  cnt8 = (!!((x>>8)&(-1))) << 3;
  x = x >> cnt8;
  cnt4 = (!!((x>>4)&(-1))) << 2;
  x = x >> cnt4;//remain 4bit
  cnt2 = (!!((x>>2)&(-1))) << 1;
  x = x >> cnt2;//remain2bit
  cnt1 = (!!((x>>1)&(-1)));
  x = x >> cnt1;
  x = cnt16+cnt8+cnt4+cnt2+cnt1 + x + 1;
  return x;
}

0xB floatScale2

输出一个小数的2倍,这个小数以unsigned int的bit来表示

unsigned floatScale2(unsigned uf)
{
  unsigned sign = uf >> 31;
  unsigned exp  = (uf >> 23 )& 0xff;
  unsigned f = uf & 0x007fffff;
  if(exp  == (1 << 8) -1 ) 
  {
    return uf;
  }
  if(!exp) 
  {
    return (sign<<31 )|(exp<<23)|(f<<1);
  }
  else 
    return (sign<<31 )|((exp+1)<<23)|(f);

  return 2;
} 

0xC floatFloat2Int

0xD floatPower2

题意:参数x, 返回2.0^x

分析:

  1. 非规格化,exp为0,偏码后为-126,frac为$2(-23)*1$,最小为$2(-149)$,所以当$x<-149$,return 0
  2. 当frac为2(-1)*,乘以*2(-126),所以非规格化最多表示$2^(-127)$ 当$-149<=x<=-127$ ,比如x = -139 的时候,前面已经乘以2(-126)*,后面再乘以*2(-13)就好了,也就是$frac = 2^(x + 126)$第$x + 126 + 24$位(从右向左)是1,return 1<<(x + 126 + 24 -1) 也即 return 1<<(x + 149)
  3. 考虑规格化数字 $1<=exp<=254$,此时减去偏码127,得到$2^(-126~127)$,所以当$-126<=x<=127$ 返回 $(127 + x) << 23$
  4. 考虑特殊值,当x >= 255,exp需要全为1,返回inf就可以了

总结

终于把datalab做完了,头疼。

原文地址:https://www.cnblogs.com/lizinuo/p/15666372.html