光天化日学C语言(14)- 位运算 & 的应用 | C语言课上学不到的哦~
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了光天化日学C语言(14)- 位运算 & 的应用 | C语言课上学不到的哦~相关的知识,希望对你有一定的参考价值。
📢博客主页:https://blog.csdn.net/WhereIsHeroFrom
📢欢迎各位 👍点赞 ⭐收藏 📝评论,如有错误请留言指正,非常感谢!
📢本文由 英雄哪里出来 原创,转载请注明出处,首发于 🙉 CSDN 🙉
作者的专栏:
👉C语言基础专栏《光天化日学C语言》
👉C语言基础配套试题详解《C语言入门100例》
👉算法进阶专栏《夜深人静写算法》
一、前言
本文作者是从 2007 年开始学 C语言 的,不久又接触了C++,基本就是 C/C++ 技术栈写了 14 年的样子,不算精通,但也算差强人意。著有《夜深人静写算法》系列,且承诺会持续更新,直到所有算法都学完。主要专攻 高中 OI 、大学 ACM、 职场 LeetCode 的全领域算法。由于文章中采用 C/C++ 的语法,于是就有不少读者朋友反馈语言层面就被劝退了,更何况是算法。
于是,2021 年 06 月 12 日,《光天化日学C语言》 应运而生。这个系列文章主要服务于高中生、大学生以及职场上想入坑C语言的志同道合之人,希望能给祖国引入更多编程方面的人才,并且让自己的青春不留遗憾!
这一章的主要内容是位与运算符的应用。
二、人物简介
- 第一位登场的就是今后会一直教我们C语言的老师 —— 光天。
- 第二位登场的则是今后会和大家一起学习C语言的没什么资质的小白程序猿 —— 化日。
三、位与运算符
- 位与运算符是一个二元的位运算符,也就是有两个操作数,表示为
x & y
。 - 位与运算会对操作数的每一位按照如下表格进行运算,对于每一位只有 0 或 1 两种情况,所以组合出来总共 2 2 = 4 2^2 = 4 22=4 种情况。
左操作数 | 右操作数 | 结果 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
- 通过这个表,我们得出一些结论:
- 1)无论是 0 或 1,只要位与上 1,还是它本身;
- 2)无论是 0 或 1,只要位与上 0,就变成 0;
#include <stdio.h>
int main() {
int a = 0b1010; // (1)
int b = 0b0110; // (2)
printf("%d\\n", (a & b) ); // (3)
return 0;
}
-
(
1
)
(1)
(1) 在C语言中,以
0b
作为前缀,表示这是一个二进制数。那么a
的实际值就是 ( 1010 ) 2 (1010)_2 (1010)2。 -
(
2
)
(2)
(2) 同样的,
b
的实际值就是 ( 0110 ) 2 (0110)_2 (0110)2; -
(
3
)
(3)
(3) 那么这里
a & b
就是对 ( 1010 ) 2 (1010)_2 (1010)2 和 ( 0110 ) 2 (0110)_2 (0110)2 的每一位做表格中的&
运算。 - 所以最后输出结果为:
2
- 因为输出的是十进制数,它的二进制表示为: ( 0010 ) 2 (0010)_2 (0010)2。
- 注意:这里的 前导零 可有可无,作者写上前导零只是为了对齐以及让读者更加清楚位与的运算方式。
四、位与运算符的应用
1、奇偶性判定
- 我们判断一个数是奇数还是偶数,往往是通过取模
%
来判断的,如下:
#include <stdio.h>
int main() {
if(5 % 2 == 1) {
printf("5是奇数\\n");
}
if(6 % 2 == 0) {
printf("6是偶数\\n");
}
return 0;
}
- 然而,我们也可以这么写:
#include <stdio.h>
int main() {
if(5 & 1) {
printf("5是奇数\\n");
}
if( (6 & 1) == 0 ) {
printf("6是偶数\\n");
}
return 0;
}
- 哇,好神奇!
- 这是利用了奇数和偶数分别的二进制数的特性,如下表所示:
- | 二进制末尾位 |
---|---|
奇数 | 1 |
偶数 | 0 |
- 所以,我们对任何一个数,通过将它和
0b1
进行位与,结果为零,则必然这个数的二进制末尾位为0,根据以上表就能得出它是偶数了;否则,就是奇数。 - 注意,由于
if
语句我们还没有实际提到过,所以这里简单提一下,后面会有系统的讲解:
if( expr ) { body }
- 对于以上语句,
expr
代表的是一个表达式,表达式的值最后只有 零 或 非零,如果值为非零,才会执行body
中的内容。
2、取末五位
【例题1】给定一个数,求它的二进制表示的末五位,以十进制输出即可。
- 这个问题的核心就是:我们只需要末五位,剩下的位我们是不需要的,所以可以将给定的数 位与上
0b11111
,这样一来就直接得到末五位的值了。 - 代码实现如下:
#include <stdio.h>
int main() {
int x;
scanf("%d", &x);
printf("%d\\n", (x & 0b11111) );
return 0;
}
【例题2】如果是想得到末七位、末九位、末十四位、末 K 位,应该如何实现呢?
3、消除末尾五位
【例题3】给定一个 32 位整数,要求消除它的末五位。
- 还是根据位与的性质,消除末五位的含义,有两层:
- 1)末五位,要全变成零;
- 2)剩下的位不变;
- 那么,根据位运算的性质,我们需要数,它的高27位都为1,低五位都为 0,则这个数就是:
- ( 11111111111111111111111111100000 ) 2 (11111111111111111111111111100000)_2 (11111111111111111111111111100000)2
- 但是如果要这么写,代码不疯掉,人也会疯掉,所以一般我们把它转成十六进制,每四个二进制位可以转成一个十六进制数,所以得到十六进制数为
0xffffffe0
。 - 代码实现如下:
#include <stdio.h>
int main() {
int x;
scanf("%d", &x);
printf("%d\\n", (x & 0xffffffe0) );
return 0;
}
4、消除末尾连续1
【例题4】给出一个整数,现在要求将这个整数转换成二进制以后,将末尾连续的1都变成0,输出改变后的数(以十进制输出即可)。
- 我们知道,这个数的二进制表示形式一定是:
- . . . 0 11...11 ⏟ k ...0\\underbrace{11...11}_{\\rm k} ...0k 11...11
- 如果,我们把这个二进制数加上1,得到的就是:
- . . . 1 00...00 ⏟ k ...1\\underbrace{00...00}_{\\rm k} ...1k 00...00
- 我们把这两个数进行位与运算,得到:
- . . . 0 00...00 ⏟ k ...0\\underbrace{00...00}_{\\rm k} ...0k 00...00
- 所以,你学会了吗?
5、2的幂判定
【例题5】请用一句话,判断一个正数是不是2的幂。
- 如果一个数是 2 的幂,它的二进制表示必然为以下形式:
- 1 00...00 ⏟ k 1\\underbrace{00...00}_{\\rm k} 1k 00...00
- 这个数的十进制值为 2 k 2^k 2k。
- 那么我们将它减一,即 2 k − 1 2^k-1 2k−1 的二进制表示如下(参考二进制减法的借位):
- 0 11...11 ⏟ k 0\\underbrace{11...11}_{\\rm k} 0k 11...11
- 于是 这两个数位与的结果为零,于是我们就知道了如果一个数
x
x
x 是 2 的幂,那么
x & (x-1)
必然为零。而其他情况则不然。 - 所以本题的答案为:
(x & (x-1)) == 0
通过这一章,我们学会了:
1)用位运算 & 来做奇偶性判定;
2)用位运算 & 获取一个数的末五位,末七位,末K位;
3)用位运算 & 消除某些二进制位;
4)用位运算 & 消除末尾连续 1;
- 希望对你有帮助哦 ~ 祝大家早日成为 C 语言大神!
课后习题
📢博客主页:https://blog.csdn.net/WhereIsHeroFrom
📢欢迎各位 👍点赞 ⭐收藏 📝评论,如有错误请留言指正,非常感谢!
📢本文由 英雄哪里出来 原创,转载请注明出处,首发于 🙉 CSDN 🙉
作者的专栏:
👉C语言基础专栏《光天化日学C语言》
👉C语言基础配套试题详解《C语言入门100例》
👉算法进阶专栏《夜深人静写算法》
以上是关于光天化日学C语言(14)- 位运算 & 的应用 | C语言课上学不到的哦~的主要内容,如果未能解决你的问题,请参考以下文章
光天化日学C语言(13)- 位运算概览 | 开启位运算的征程
光天化日学C语言(16)- 位运算 ^ 的应用 | 最神奇的异或运算
光天化日学C语言(18)- 位运算 << 的应用 | 左移的一些高端用法