C语言每日一练 —— 第20天:位运算
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言每日一练 —— 第20天:位运算相关的知识,希望对你有一定的参考价值。
文章目录
一、前言
今天主要内容是聊一聊二进制和位运算。
对应视频教程如下:位运算视频教程。
二、再谈二进制
我们在学习 光天化日学C语言(06)- 进制转换入门 的时候,曾经提到过二进制。
二进制就是逢二进一,计算机中的存储采用的就是二进制。在计算机中,非零即一。
1、二进制数值表示
例如,在计算机中,我们可以用单纯的 0 和 1 来表示数字。
1、101、1100011、100101010101 都是二进制数。
123、423424324、101020102101AF 则不是,因为有 0 和 1 以外的数字位。
一般为了不产生二义性,我们会在数字的右下角写上它的进制,例如: 101 0 ( 10 ) 1010_(10) 1010(10) 代表的是十进制下的 1010,也就是十进制下的 “一千零一十”。 101 0 ( 2 ) 1010_(2) 1010(2) 代表的是二进制下的 1010,也就是十进制下的 “十”。
2、二进制加法
二进制加法采用从低到高的位依次相加,当相加的和为2时,则向高位进位。
例如,在二进制中,加法如下: 1 ( 2 ) + 1 ( 2 ) = 1 0 ( 2 ) 1 ( 2 ) + 0 ( 2 ) = 1 ( 2 ) 0 ( 2 ) + 1 ( 2 ) = 1 ( 2 ) 0 ( 2 ) + 0 ( 2 ) = 0 ( 2 ) 1_(2) + 1_(2) = 10_(2) \\\\ 1_(2) + 0_(2) = 1_(2) \\\\ 0_(2) + 1_(2) = 1_(2) \\\\ 0_(2) + 0_(2) = 0_(2) 1(2)+1(2)=10(2)1(2)+0(2)=1(2)0(2)+1(2)=1(2)0(2)+0(2)=0(2)
3、二进制减法
二进制减法采用从低到高的位依次相减,当遇到 0 减 1 的情况,则向高位借位。
例如,在二进制中:减法如下: 1 ( 2 ) − 1 ( 2 ) = 0 ( 2 ) 1 ( 2 ) − 0 ( 2 ) = 1 ( 2 ) 1 0 ( 2 ) − 1 ( 2 ) = 1 ( 2 ) 0 ( 2 ) − 0 ( 2 ) = 0 ( 2 ) 1_(2) - 1_(2) = 0_(2) \\\\ 1_(2) - 0_(2) = 1_(2) \\\\ 10_(2) - 1_(2) = 1_(2) \\\\ 0_(2) - 0_(2) = 0_(2) 1(2)−1(2)=0(2)1(2)−0(2)=1(2)10(2)−1(2)=1(2)0(2)−0(2)=0(2) 而我们今天要讲的位运算正是基于二进制展开的。
三、位运算简介
位运算可以理解成对二进制数字上的每一个位进行操作的运算。位运算分为 逻辑(布尔)位运算符 和 移位位运算符。
逻辑位运算符又分为 位与(&)、位或(|)、异或(^)、按位取反(~);移位位运算符分为 左移(<<) 和 右移(>>)。
如图所示:
1、位与的定义
位与运算符是一个二元的位运算符,也就是有两个操作数,表示为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。注意:这里的 前导零 可有可无,作者写上前导零只是为了对齐以及让读者更加清楚位与的运算方式。
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,根据以上表就能得出它是偶数了;否则,就是奇数。
2)取末五位
给定一个数,求它的二进制表示的末五位,以十进制输出即可。
这个问题的核心就是:我们只需要末五位,剩下的位我们是不需要的,所以可以将给定的数 位与上0b11111
,这样一来就直接得到末五位的值了。代码实现如下:
#include <stdio.h>
int main()
int x;
scanf("%d", &x);
printf("%d\\n", (x & 0b11111) );
return 0;
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)2的幂判定
请用一句话,判断一个正数是不是2的幂。
如果一个数是 2 的幂,它的二进制表示必然为以下形式: 1 00...00 ⏟ k 1\\underbrace00...00_\\rm k 1k 00...00 这个数的十进制值为 2 k 2^k 2k。那么我们将它减一,即 2 k − 1 2^k-1 2k−1 的二进制表示如下(参考二进制减法的借位): 0 11...11 ⏟ k 0\\underbrace11...11_\\rm k 0k 11...11于是 这两个数位与的结果为零,于是我们就知道
以上是关于C语言每日一练 —— 第20天:位运算的主要内容,如果未能解决你的问题,请参考以下文章