0x01 位运算(1)

0x01 位运算(1)

本节主要内容:

第一部分:补码反码、移位运算、快速幂、快速乘法

第二部分:二进制状压、成对变换、lowbit()运算,Barrett模乘(补充)

一、 补码与反码

1. 补码

开头一个符号位,其余为数值位

32位补码表示unsigned intint
000000...00000000
0111111...11111121474836472147483647
100000...0000002147483678-2147483648
111111...1111114294967295-1
1. 反码

开头一个符号位,其余为数值位

32位反码表示32位整数
000000...0000000
111111...1111110
011111...1111112147483647
100000...000000-2147483647

二、 移位运算

  1. 算术右移:高位以符号位补充,低位越界舍弃

  2. 逻辑右移:高位以0补充,低位越界舍弃

三、 快速幂取模

此时尝试计算

$$
a^bmod\quad p
$$

这是一个典型的求幂运算,在一些与数学有关的问题中极为常见。

通常使用循环方法求幂,时间复杂度为O(b),然而众所周知,取模运算的速度极慢,这种暴力方法不足以满足我们的需求,我们需要尽可能减少运算次数。

接下来介绍利用位运算加速的求幂方法,先给出理论推导

假设指数b在二进制下表示为

$$
b_{(2)} = \overline{c_{k-1}c_{k-2} \dots c_0}
$$

写为多项式,即为

$$
b = c_{k-1} \cdot 2^{k-1} + c_{k-2} \cdot 2^{k-2} + \dots + c_0\cdot2^0
$$

从而

$$
\begin{aligned} a^b &= a^{c_{k-1}\cdot{2^{k-1}}} * a^{c_{k-2}\cdot{2^{k-1}}}*\dots*a^{c_0*2^0}\\ &=(a^{c_{k-1}\cdot{2^{k-2}}} * a^{c_{k-2}\cdot{2^{k-3}}}*\dots*a^{c_1*2^0})^2*a^{c_0\cdot2^0}\\ &=((a^{c_{k-1}\cdot{2^{k-3}}} * a^{c_{k-2}\cdot{2^{k-4}}}*\dots*a^{{c_2}*2^0})^2*a^{c_1*2^0})^2*a^{c_0\cdot2^0}\\ &=\dots\\ &=(((a^{c_{k-1}\cdot2^0})^2*a^{c_{k-2}\cdot2^0})^2*\dots)^2*a^{c_0\cdot2^0}\\ &=(((a^{c_{k-1}})^2*a^{c_{k-2}})^2*\dots)^2*a^{c_0} \end{aligned}
$$

于是,可以用下面的代码求出a^b:

int power(int a,int b){   //calculate a^b
    int ans = 1;
    while(b){
        if (b & 1) ans *= a;
        a *= a;
        b >>= 1;
    }
    return ans;
}

同时,考虑到

$$
a\cdot b \quad \%p == a\%p\quad\cdot\quad b\%p
$$

则在循环中每次计算取模

int power(int a,int b, int p){   //calculate a^b
    int ans = 1 % p;
    while(b){
        if (b&1) ans = (ll)ans * a  % p;//暂时转化为ll,以免越界,赋值时再转化回int
        a = (ll)a * a % p;
        b >>= 1;
    }
    return ans;
}

从而,我们计算出a^b mod p,时间复杂度为O(log2b)

四、 64位整数乘法

题目链接:64位整数乘法——ACWing

类似于快速幂取模,我们用相似的方法处理乘法。

此时尝试计算

$$
ab\quad mod\quad p
$$

假设b在二进制下表示为

$$
b = \overline{c_{k-1}c_{k-1}\dots c_0}
$$

写为多项式,即为

$$
b = c_{k-1} \cdot 2^{k-1} + c_{k-2} \cdot 2^{k-2} + \dots + c_0 \cdot 2^0
$$

从而

$$
\begin{aligned} ab &= ac_{k-1}\cdot 2^{k-1}+ac_{k-2}\cdot2^{k-2}+\dots+ac_0\cdot2^0\\ &= (ac_{k-1}\cdot 2^{k-2} + ac_{k-2}\cdot2^{k-3}+\dots+ac_1\cdot2^0)*2+ac_0\cdot2^0\\ &= ((ac_{k-1}\cdot 2^{k-3} + ac_{k-2}\cdot2^{k-4}+\dots+ac_2\cdot2^0)*2+ac_1\cdot2^0)*2+ac_0\cdot2^0\\ &=\dots\\ &=(((ac_{k-1}\cdot2^0)*2+ac_{k-2}\cdot2^0)*2+\dots)*2+ac_0\cdot2^0\\ &=((ac_{k-1}*2+ac_{k-2})*2+\dots)*2+ac_0\\ &=[((c_{k-1}*2+c_{k-2})*2+\dots)*2+c_0]\cdot a\\ \end{aligned}
$$

于是,可以用下面的代码求出ab

ll mul(ll a, ll b){
    ll ans = 0;
    while(b){
        if (b & 1) ans += a;
        a *= 2;
        b >>= 1;
    }
    return ans;
}

考虑取模:

ll mul(ll a, ll b){
    ll ans = 0;
    while(b){
        if (b & 1) ans = (ans + a) % p;
        a = a * 2 % p;
        b >>= 1;
    }
    return ans;
}

从而,我们计算出ab mod p,时间复杂度为O(log2b)

本文由“小苏打NaHCO3”原创,未经允许,严禁转载!

如果觉得本文对你有用,不妨点赞收藏一下吧!

### C语言中 `X` 与 `0x01` 进行按位与运算的结果 在C语言中,按位与运算符 (`&`) 是一种二元操作符,它会对两个整数的操作数逐位执行逻辑与操作。对于表达式 `X & 0x01` 的结果分析如下: #### 按位与运算原理 - 数字 `0x01` 表示十六进制的数值,在二进制下等于 `00000001`。 - 当任何数字 `X` 和 `0x01` 执行按位与操作时,只有 `X` 的最低有效位(Least Significant Bit, LSB)会被保留下来[^2]。 #### 计算过程 假设 `X` 是一个任意整数,则其二进制形式可能为: ```plaintext X = b_n ... b_3 b_2 b_1 ``` 其中 `b_i` 表示第 `i` 位上的值(01),而最低有效位是 `b_1`。 当 `X` 与 `0x01` 进行按位与操作时,计算方式如下: ```plaintext X = b_n ... b_3 b_2 b_1 AND 0x01 = 0 ... 0 0 1 ----------------------------------- Result = 0 ... 0 0 b_1 ``` 因此,最终结果只取决于 `X` 的最低有效位 `b_1`。如果 `b_1` 为 `1`,则结果为 `1`;如果 `b_1` 为 `0`,则结果为 `0`[^2]。 #### 应用场景 这种运算通常用于判断某个整数是否为奇数或偶数。因为在一个整数的二进制表示中,最低有效位决定了该数的奇偶性: - 如果最低有效位为 `1`,说明该数是奇数; - 如果最低有效位为 `0`,说明该数是偶数。 以下是实现这一功能的一个例子: ```c #include <stdio.h> int main() { int num; printf("Enter an integer: "); scanf("%d", &num); if ((num & 0x01) == 1) { // 判断最低有效位是否为1 printf("%d is odd.\n", num); } else { printf("%d is even.\n", num); } return 0; } ``` 通过以上代码可以看出,`(num & 0x01)` 可以用来提取输入整数的最低有效位并据此判断奇偶性[^2]。 ### 总结 在C语言中,`X & 0x01` 的结果仅反映 `X` 的最低有效位的状态。此运算常用于检测整数的奇偶性或其他基于最低有效位的应用场合。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值