• 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是最为简单的做法,数组的下标即为列,再存上对应的行数,即能够确定整个八皇后的状态。
  • 相关阅读:
    centos7/RHEL7安装LibreOffice
    CentOS7开机启动管理systemd简介及使用
    Vim使用技巧
    16_用LVM扩展xfs文件系统(当分区空间不够时)
    15_RHEL7挂载NTFS分区
    14_RHEL7安装mplayer
    polyfill-eventsource added missing EventSource to window ie浏览器 解决方案
    关于vue,webpack 中 “exports is not defined”报错
    2018 vue前端面试题
    Error: No PostCSS Config found in... 报错 踩坑记
  • 原文地址:https://www.cnblogs.com/wheszza/p/13258117.html
Copyright © 2020-2023  润新知