zoukankan      html  css  js  c++  java
  • 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做完了,头疼。

  • 相关阅读:
    Java实现第八届蓝桥杯9算数式
    Java实现第八届蓝桥杯9算数式
    java实现第七届蓝桥杯寒假作业
    java实现第七届蓝桥杯寒假作业
    java实现第六届蓝桥杯隔行变色
    java实现第六届蓝桥杯无穷分数
    mysql-5.7.19-winx64服务无法启动解决方案
    MySQL集群搭建详解
    Windows下多个Mysql实例配置主从
    在一台机子上,安装,运行两mysql数据库实例
  • 原文地址:https://www.cnblogs.com/lizinuo/p/15666372.html
Copyright © 2011-2022 走看看