【c/c++学习】与或非的奇技淫巧

整理一下&、||、!的奇技淫巧

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的次幂。

未完待续......

参考:HashMap算法:x%y=x&(y-1)_程序员阿坤的博客-CSDN博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值