位运算chapter5:提取一个数二进制表达式末位0的个数

基本概念

一个数的二进制表示末尾0的个数表示该数能够被2连续整除的次数。例如:

  • 8 的二进制表示为 1000,末尾有3个0。
  • 12 的二进制表示为 1100,末尾有2个0。

使用位运算提取末尾0的个数

通过位运算,可以高效地计算一个整数末尾0的个数。具体方法如下:

  1. 位运算方法

    int ZeroBit(int n) {
        return log2f(n & -n);
    }
    
  2. 说明

    • n & -n 提取了 n 的二进制表示中最右边的1及其右边所有的0,这样我们就能得到一个只有最右边1位为1的数。

      下面以24为例演示n & -n的过程
      11000  (n)
      01000  (-n)
      ------
      01000  (n & -n)
    • log2f 计算这个数的二进制对数,也就是末尾0的个数。

示例代码

下面是完整的示例代码,用于提取一个整数末尾0的个数:

#include <iostream>
#include <cmath>

int ZeroBit(int n) {
    return log2f(n & -n);
}

int main() {//k为n的二进制表达式末位'0'的个数
    unsigned long k;
    int n;
    std::cin >> n;
    
    _BitScanForward(&k, n);//在Visual Studio编译器下使用
    std::cout << k << '\n';
    std::cout << ZeroBit(n) << '\n';
    
    return 0;
}
// 在GCC或G++中,应使用 __builtin_ctz(n)
//具体使用方法如下
// unsigned long k = __builtin_ctz(n);

                                                                                                上述三种方法的时间复杂度都是O(1)

解释 

  1. 输入输出

    • 输入一个整数 n
    • 使用 _BitScanForward 或 __builtin_ctz 提取末尾0的个数并输出。
    • 使用 ZeroBit 函数提取末尾0的个数并输出。
  2. 函数使用

    • _BitScanForward(&k, n) 是 MSVC 特有的函数,在编译器为Visual Studio C++的时候使用这个函数。在某些编译器下,可能需要加头文件#include<intrin.h>。在函数的调用过程中,'&'引用符号不可以省略,否则k无法被写入。
    • __builtin_ctz(n) 是 GCC 和 Clang 中的内置函数,在编译器为GCC或G++的时候使用这个函数。直接使用不需要加头文件。
    • ZeroBit(n) 函数为自定义,万用。

 实例

        输入一个正整数,求这个数的最大的奇因数。先做个因数和最大基因数概念的简易阐述。

因数

因数(或称为约数)是能被一个整数整除的数。例如,12的因数包括:1, 2, 3, 4, 6, 12,因为12能够被这些数整除而没有余数。

  • 6的因数是:1, 2, 3, 6
  • 15的因数是:1, 3, 5, 15

最大奇因数

最大奇因数是一个整数的所有因数中最大的奇数因数。奇数因数是指不能被2整除的因数。

  • 对于12:

    • 因数包括:1, 2, 3, 4, 6, 12
    • 其中奇数因数是:1, 3
    • 最大奇因数是:3
  • 对于18:

    • 因数包括:1, 2, 3, 6, 9, 18
    • 其中奇数因数是:1, 3, 9
    • 最大奇因数是:9

下面给出函数部分。

// 函数:求最大奇因数
int Odd(int n) {
    return n / (n & -n);
}

解释

  1. Odd函数

    • n & -n 提取了 n 的二进制表示中最右边的1及其右边所有的0,这样我们就能得到一个只有最右边1位为1的数。
    • n / (n & -n) 将原数 n 除以这个数,去除了所有的2的幂因子,剩下的就是最大的奇因数。
    • 时间复杂度O(1)。

当然,利用​​​​​​​​​​​​​​ _BitScanForward(&k, n)__builtin_ctz(n)也可以实现。时间复杂度也是O(1)。

int Odd(int n) {
    unsigned long k;
    _BitScanForward(&k, n);
    return n >> k;
}

int Odd(int n) {
    int k = __builtin_ctz(n);
    return n >> k;
}

                                                                                  谢谢观看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值