详解一种高效位反转算法

位反转

这里的位反转(Bit Reversal),指的是一个数的所有bit位依照中点对换位置,例如0b0101 0111 => 0b1110 1010。也可以叫二进制逆序,按位逆序,位翻转等等。

算法原理

高效位反转算法原理: 算法运用了分治法(divide and conquer),以两个bit位一组,对调相邻的bit位;然后再以4个bit位为一组,分成左边两个bit位一段和右边两个bit位一段,然后这两段相互对调;然后再以8个bit位为一组,以此类推,最后完成位反转。

32位数的高效位反转算法实现

下面举例一个32位数的高效位反转算法代码:

unsigned int reverse(unsigned int x) {
    x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
    x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
    x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
    x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
    return((x >> 16) | (x << 16));
}

下面进行逐行代码分析:

首先,我们要进行位反转的是一个32位数,如下图所示
在这里插入图片描述

分析第一行代码:

x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));

在这里插入图片描述

  1. 0xaaaaaaaa
    0xaaaaaaaa 是从第0位开始,所有奇数位为1
    0xaaaaaaaa = 0b10101010101010101010101010101010

  2. x & 0xaaaaaaaa
    x & 0xaaaaaaaa的结果如下图所示:

在这里插入图片描述

  1. (x & 0xaaaaaaaa) >> 1
    右移一位后结果如下图所示:

在这里插入图片描述

  1. 0x55555555
    0x55555555是从第0位开始,所有偶数位为1
    0x55555555 = 0b01010101010101010101010101010101

  2. x & 0x55555555
    x & 0x55555555的结果如下图所示:

在这里插入图片描述

  1. (x & 0x55555555) << 1
    左移一位的结果如下图所示:

在这里插入图片描述

  1. x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
    然后两个数或运算,结果如下图所示:

在这里插入图片描述
第一行代码运算完成。
总结,x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));这行的代码就是以两个bit位一组,对调相邻的bit位。
图解就是将下图
转换为转换为在这里插入图片描述

分析第二行代码:

x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));

目前x的数值为:
在这里插入图片描述

  1. 0xcccccccc
    0xcccccccc是从第0位开始,0和1每隔两位交替出现0
    xcccccccc = 0b11001100110011001100110011001100

  2. x & 0xcccccccc
    x & 0xcccccccc的结果如下图所示:

在这里插入图片描述

  1. (x & 0xcccccccc) >> 2
    右移两位后结果如下图所示:
    在这里插入图片描述
  2. 0x33333333
    0x33333333是从第0位开始,1和0每隔两位交替出现
    0x33333333 = 0b00110011001100110011001100110011
  3. x & 0x33333333
    x & 0x33333333的结果如下图所示:

在这里插入图片描述

  1. (x & 0x33333333) << 2
    左移两位后结果如下图所示:

在这里插入图片描述

  1. x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
    然后两个数或运算,结果如下图所示:

在这里插入图片描述
第二行代码运算完成。
总结,x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));这行的代码就是以4个bit位为一组,分成左边两个bit位一段和右边两个bit位一段,然后这两段相互对调。
图解就是将下图
在这里插入图片描述
转换为
在这里插入图片描述

分析第三行代码:

x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));

目前x的数值为:
在这里插入图片描述

  1. 0xf0f0f0f0
    0xf0f0f0f0是从第0位开始,0和1每隔四位交替出现
    0xf0f0f0f0= 0b11110000111100001111000011110000

  2. x & 0xf0f0f0f0
    x & 0xf0f0f0f0的结果如下图所示:

在这里插入图片描述

  1. (x & 0xf0f0f0f0) >> 4
    右移四位后结果如下图所示:

在这里插入图片描述

  1. 0x0f0f0f0f
    0x0f0f0f0f是从第0位开始,1和0每隔四位交替出现
    0x0f0f0f0f= 0b00001111000011110000111100001111

  2. x & 0x0f0f0f0f
    x & 0x0f0f0f0f的结果如下图所示:

在这里插入图片描述

  1. (x & 0x0f0f0f0f) << 4
    左移四位后结果如下图所示:

在这里插入图片描述

  1. x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
    然后两个数或运算,结果如下图所示:

在这里插入图片描述
第三行代码运算完成。
总结,x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));这行的代码就是以8个bit位为一组,分成左边四个bit位一段和右边四个bit位一段,然后这两段相互对调。
图解就是将下图
在这里插入图片描述
转换为
在这里插入图片描述

分析第四行代码:

x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));

目前x的数值为:
在这里插入图片描述

  1. 0xff00ff00
    0xff00ff00是从第0位开始,0和1每隔八位交替出现
    0xff00ff00= 0b11111111000000001111111100000000

  2. x & 0xff00ff00
    x & 0xff00ff00的结果如下图所示:

在这里插入图片描述

  1. (x & 0xff00ff00) >> 8
    右移八位后结果如下图所示:

在这里插入图片描述

  1. 0x00ff00ff
    0x00ff00ff是从第0位开始,1和0每隔八位交替出现
    0x00ff00ff= 0b00000000111111110000000011111111

  2. x & 0x00ff00ff
    x & 0x00ff00ff的结果如下图所示:

在这里插入图片描述

  1. (x & 0x00ff00ff) << 8
    左移八位后结果如下图所示:

在这里插入图片描述

  1. x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
    然后两个数或运算,结果如下图所示:

在这里插入图片描述
第四行代码运算完成。
总结,x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));这行的代码就是以16个bit位为一组,分成左边八个bit位一段和右边八个bit位一段,然后这两段相互对调。

图解就是将下图
在这里插入图片描述
转换成
在这里插入图片描述

分析最后一行代码:

((x >> 16) | (x << 16))

目前x的数值为
在这里插入图片描述
高16bit与低16bit进行交换,结果如下图:
在这里插入图片描述
完成整个位反转算法。

8位数的高效位反转算法实现

如果要对8位数进行位反转,原理相同,代码如下:

unsigned char reverse(unsigned char x) {
    x = (((x & 0xaa) >> 1) | ((x & 0x55) << 1));
    x = (((x & 0xcc) >> 2) | ((x & 0x33) << 2));
    return ((x >> 4) | (x << 4));
}

即可实现对8位数的高效位反转。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值