zoukankan      html  css  js  c++  java
  • Lesson 3 : Bit Hacks

    Lesson 3 : Bit Hacks

    1. Binary Representaion

    x + ~x = -1 // 现在所有位均为1,补码均为1时结果为-1
    -x = ~x + 1 // 由上式可推出
    

    2. Some Tricks

    下面的代码可以通过c实现,别的语言可能无法实现。

    2.1 No-Temp Swap

    x = x ^ y;
    y = x ^ y;
    x = x ^ y;
    

    这是因为(x ^ y) ^ y => x;
    证明如下:
    x = x ^ y, 这时x储存的值设定为了:x,y相同的数据的位置的值为0,不同数据的位置的值为1。
    y = x ^ y, x, y相同数据的位置的值为0,与y异或,得到的值为x,y中相同的数据,x,y不同数据的位置的值为1,与y异或,得到的值与y中数据相反,即为x中的数据。现在,y值就变成了x,因为相同数据的位置的值不变,不同数据的值取反。
    按照上面的推理可以推出x = x ^ y后x的值为之前y的值。

    这种方式并不一定高效,因为这三个指令必须顺序执行。如果采用temp的方式,后面的两个指令可以并行执行。

    2.2 No-Branch Minimum

    r = y ^ ((x ^ y) & -(x < y))
    

    证明如下:
    情况1,x < y:则-(x < y) = -1,即所有位均为1,任何值&所有位均为1的数据还是其本身,于是 r = y ^ (x ^ y),根据2.1中的证明, y ^ (x ^ y) = x,于是,r = x。
    情况2,x > y: 则-(x > y) = 0,即所有位均为0,任何值&所有位均为0的数据还是0,于是r = y ^ (0) = y。证毕。
    优化分支的方式在大多数现在编译器上效果不好,这是因为编译器会对分支进行优化,比我们简单处理的优化结果要好

    2.3 No-Branch Mod

    Problem: z = x + y, 0 ≤ x < n, 0 ≤ y < n, r = z % n, 求r

    //Normal
    z = x + y;
    if(z > r) r = z - n;
    else r = z;
    //equal to r = (z > n) ? z - n : z
    //No-Branch
    r = z -(n & (z ≥ n))
    

    证明方法与2.2类似。

    2.4 Least Significant

    Problem: 找到x中最低位的1

    r = x & (-x);
    

    证明:因为-x = ~x + 1,假设x中第i位是最低位的1,所以比i位低的位均为0,那么取反之后比i位低的位均为1,第i位为0,比i位高的为相应位置x取反。加上1之后,比i位低的位均变成了0,而第i位为1,比i位高的仍为相应位置x取反。我们可以发现,比i高的位是x取反,i位及低于i位的与x相同,但第i位为1,低于i位的为0。所以,经过&操作后,r值第i位为1,其余位置均为0。
    PS:可以通过lgr的方式求解i。

    2.5 Population Count 1

    Problem: 计算x中1的数量

    for(r = 0; x != 0; ++r)
        x &= x -1;
    

    证明:我们看一下x &= x -1的值究竟是什么,我们假设第i位为最低位的1,那么在x中第i为1,比第i位低的为0,在x-1中,第i位为0,比第i位低的为1,比i高的位中数据相同。那么x &= x -1就等于x将最低位的1变成0的后值,即记录了一个1。
    我们可以发现,上面的代码执行速度与x中1的数量正相关,下面给出与1的数量无关的算法。

    //我们假设使用的机器为64位
    M0 = ~(-1 << 32);     //
    M1 = M0 ^(M0 << 16);
    M2 = M1 ^(M1 << 8);
    M3 = M2 ^(M2 << 4);
    M4 = M3 ^(M3 << 2);
    M5 = M4 ^(M4 << 1);
    
    x = ((x >> 1) & M5) + (x & M5);
    x = ((x >> 2) & M4) + (x & M4);
    x = ((x >> 4) + x) & M3;
    x = ((x >> 8) + x) & M2;
    x = ((x >> 16) + x) & M1;
    x = ((x >> 32) + x) & M0;
    

    第一次计算出的为每2位1的数量,存到x,
    第二次计算出的为每4位1的数量,存到x,
    第三次计算出的为每8位1的数量,存到x,
    第四次计算出的为每16位1的数量,存到x,
    第五次计算出的为每32位1的数量,存到x,
    第六次计算出的为每64位1的数量,存到x。

    2.6 Board Representation

    Problem: 如何表示八皇后的状态,最节省空间的做法是什么

    1. n*n的矩阵(byte)
    2. n*n的矩阵(bit)
    3. n大小的数组(byte)
    4. 3 bitvectors of size n, 2n-1, and 2n-1(bit).
      方式4是最为节省空间的做法,采用down数组存放列状态,left数组存放左斜状态,right数据存放右斜状态。(数组中的每个元素大小为bit)
      方式3是最为简单的做法,数组的下标即为列,再存上对应的行数,即能够确定整个八皇后的状态。
  • 相关阅读:
    jsp 特殊标签
    poj 1753 Flip Game 高斯消元 异或方程组 求最值
    zoj 3155 Street Lamp 高斯消元 异或方程组 求方案数
    poj1222 EXTENDED LIGHTS OUT 高斯消元解异或方程组 模板
    zoj 3930 Dice Notation 模拟
    zoj 3157 Weapon 线段树求逆序对数
    hdu 1242 Rescue BFS+优先队列
    hdu 3466 Proud Merchants 贪心+01背包
    zoj 3689 Digging 贪心+01背包
    hdu 2602 Bone Collector 01背包模板
  • 原文地址:https://www.cnblogs.com/wheszza/p/13258117.html
Copyright © 2011-2022 走看看