整理一下&、||、!的奇技淫巧
1 x&(x-1)是什么意思
京东有一道笔试题
/*************************************************************************
> File Name: test.cpp
> Author: Winter
> Created Time: 2022年08月07日 星期日 16时12分42秒
************************************************************************/
#include <iostream>
using namespace std;
int func(int x)
{
int count = 0;
while (x)
{
count++;
x = x & (x - 1);
}
return count;
}
int main(int argc, char** argv)
{
cout << func(2015) << endl;
return 0;
}
就是x的二进制与x-1的二进制进行与运算;
再深挖一步,x-1的二进制就是把x的二进制的最右侧一个1变成0。
第一次 x & (x - 1)的结果就是把x最右侧的第一个1变成0(去掉1),再将结果赋值给x,计数器++;
......
所以 x & (x - 1)是统计x的二进制中有多少个1
上述代码结果
2015比1024大(2的10次方),但是小于2048(2的11次方)。
2 求一个数最右侧的1是哪一位
例如:
1 = (001)------->0 (从第0位开始计数,1在第0位)
2 = (010)------->1 (从第0位开始计数,1在第1位)
3 = (011)------->0 (从第0位开始计数,1在第0位)
4 = (100)------->2 (从第0位开始计数,1在第2位)
5 = (101)------->0 (从第0位开始计数,1在第0位)
......
首先从最低位开始判断,怎么判断呢?
想到与或非运算符。当x=1时,x&1才是1
#include <iostream>
using namespace std;
int func(int x)
{
int count = 0;
int res = 1;
while (1)
{
if (x & res) {
break;
}
count++;
res = res << 1;
}
return count;
}
int main(int argc, char** argv)
{
cout << func(1) << endl;
cout << func(2) << endl;
cout << func(3) << endl;
cout << func(4) << endl;
cout << func(5) << endl;
return 0;
}
结果
如果要计算具体是多少,用2累乘即可。
3 求一个数最右侧的0是哪一位
例如:
1 = (001)------->1 (从第0位开始计数,1在第1位)
2 = (010)------->0 (从第0位开始计数,1在第0位)
3 = (011)------->2 (从第0位开始计数,1在第2位)
4 = (100)------->0 (从第0位开始计数,1在第0位)
5 = (101)------->1 (从第0位开始计数,1在第1位)
......
#include <iostream>
using namespace std;
int func(int n) {
int res = 0;
while (n & 1) {
n = n >> 1;
res++;
}
return res;
}
int main(int argc, char** argv)
{
cout << func(1) << endl;
cout << func(2) << endl;
cout << func(3) << endl;
cout << func(4) << endl;
cout << func(5) << endl;
return 0;
}
结果
4 求一个数最左侧的1是哪一位
#include <iostream>
using namespace std;
int func(int n)
{
int pos=-1;
while (n)
{
n>>=1;
pos++;
}
return pos;
}
int main(int argc, char** argv)
{
cout << func(1) << endl;
cout << func(2) << endl;
cout << func(3) << endl;
cout << func(4) << endl;
cout << func(5) << endl;
return 0;
}
结果
5 x%y=x&(y-1)
这个是在leveldb源码中看到的三行代码
const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8;
static_assert((align & (align - 1)) == 0,
"Pointer size should be a power of 2");
size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align - 1);
第一句:指针大小是4/8(32机器人是4字节,64位机器是8字节),所以align的值总是8
第二句:这是一句断言。如果一个数x,是2的n次方,那么这个数用二进制表示时其最高位为1,其余位为0。则(x-1)的二进制就是01111111.....1。则其与x与之后就是0,所以x&(x-1)) == 0为真,表明x是2的n次方,否则x不是2的n次方。
第三句:y & (x - 1),对应的y % x
注意:x必须是2的次幂。
未完待续......