每日一题——另类加法(位运算)
在编程语言的学习中最令我头疼的就是,一些基于比特位的运算,因为这些运算并不会将自己的结果呈现给你,而是以具体十进制数字的状态返回给你,但是它的内部进行的是比特位的计算这一部分的计算只能通过你的想象进行复现。故让人,摸不着头脑。今天我们来简单列举一些位运算的用法。
本文由爱吃苹果的清梦,友情提供
文章目录
简介
对于位运算,我了解到的有以下几种运算:
lowbit运算
这个运用是比较经典使用方法,其基本的运用是,判断这个数二进制位上的最后一个1在第几位上,也就是说返回最后一个一和后边的零组成的数究竟是2的几次方进行判断。
基本形式: x & (-x);
原理:因为当
x
转换成-x
的时候,它在内存中的保存形式就会发生变化,由正数的原码发生变化,变成负数的补码进行保存,因为最后一个1
后边全是0
,所以在第一步转换成反码的时候就会全变成1,而1本身就会变成0,然后变成补码加一,我们只看结果的话,会发现其实最后一个**1
的位置根本没发生变化,但是其他都会被&
**操作变成0。演示图片
对于数的二进制每位的查看
刚开始学位运算的时候我接触的第一个具体应用就是这个,因为变量存储的时候展现的是十进制的内容,但是我们要通过一定的方法对二进制进行查看。所以这个应用便脱颖而出。
基本形式: x >> i & j;
**含义:**其实就是x,第i位和1相与的结果。
对于数电中加法器的实现:
由一定数电基础的同学都知道,数电存在着门电路,和计算机的按位操作十分类似。所以既然有门电路实现的加法器,那么我们可不可以将全加器加以扩展用来实现两个数之间的加法呢??
答案是肯定的,根据原理图就可以实现。
原理图:
根据逻辑表达式我们可得:
sum = a ^ b ^ c
c = (a ^ b) & c | (a & b)
这只是一个位的操作,但是我们如果直接对32位进行操作的话不就直接完成了整数的加减了。
实现交换
其实实现交换也是借用了异或这一操作符的特性,具体操作如下
int a = 0; int b = 1; int c = a ^b; a ^= a; b ^= b;
这样便实现了交换
判断缺少
基本原理就是,异或的基本原理,在一段重复的序列中,找那个没有重复的序列,直接异或剩下的那个就是,只不过,这个有一个变形题值得注意,找单身狗。
其他应用
x & (x - 1);
这个是数一个数中有多少个1
不用加减乘除做加法(对于数电中的加法器实现)
题目描述
题目解析
本题既然ban掉了四则运算的运算符号,那么,我们就要联想到要用位运算进行操作,下面提供两个思路:
方法一: 根据加法的原理进行递归实现
其实我们把相加的两个数进行拆分我们就可以发现,其实加法就是,进位和对位相加的一个结果,那么,我们用一个变量模拟按位相加,一个模拟进位就可以了。然后将进位消耗完,就是我们要的那一个数了。
方法二:利用数电的全加器进行实现
如同上文讲的一样。
方法一——代码实现
class Solution {
public:
int Add(int num1, int num2) {
if(!num2) return num1;
int tem = num1 ^ num2;
int ret = (num1 & num2) << 1;
return Add(tem,ret);
}
};
方法二——代码实现
class Solution {
public:
int Add(int num1, int num2) {
int c = 0;
int arr[32] = {0};
for (int i = 0; i < 32; i++)
{
int a = num1 >> i & 1;
int b = num2 >> i & 1;
arr[i] = a ^ b ^ c;
c = (a & b) | (c & (a ^ b));
}
reverse(arr, arr + 32);
int sum = 0;
for (auto i : arr)
{
sum ^= i;
sum <<= 1;
}
return sum >> 1;
}
};
//类比数电的加法器进行实现
后记
按位操作,还有很多妙用,诸如线段树啥的都会用到。