位运算

二进制

计算机都是用的二级制运算的,别问为啥,问就是计算机只会01计算,算不到2
具体二进制运算等一些操作可以百度一下,或者看一下这个,(我百度搜的)

比如21的二进制是10101

二进制运算

  • 二进制运算和普通加减乘除运算差不多,都是几个数一顿操作最后得出另一个数,比如1+0=1,比如1&0=0

与运算(逻辑乘法)

  • 与(&)运算:都1为1,否则为0

比如5&4
5:101
4:100
=:100=4

比如17&21
11: 1011
21:10101
&=:00001 =1
11的二进制是四位,21的二进制是五位,运算的时候后端对齐,前端补零(前面补多少个都可以,反正计算机也不会站起来打你),所以11相当于01011

或(逻辑加法)

  • 或(|)运算:都0为0,否则为1

比如5&4
5:101
4:100
=:101=5

比如17&21
11:01011
21:10101
|=:11111 =31

非运算(逻辑否定)

  • 非(~)运算:0为1,1为0

比如~5
5:101
~:010 =2

但是你们在编译器上打出来绝对不会是2,实际上等于-6,因为还涉及到负数形式(负数相关操作)

  • 此样例只是说明非运算是使0成1,1成0,不要被误导

<<左移运算

  • 左移运算就是向左移动

21的二进制是10101
左移就是将他二进制整个向左移动
21<<1就是21的二进制10101向左移动1位:101010 = 42
42<<1就是42的二进制101010向左移动1位:1010100 = 84
21<<2就是21的二进制10101向左移动2位:1010100 = 84

  • 左移运算就是将整个二进制向左移动几位,右边增加的位置补0即可
  • 左移运算其实就是乘以2,所以在写代码的时候如果有乘以2,4,8…的情况可以用左移1,2,3…位来完成,因为位运算的执行效率比乘法高

>>右移运算

  • 右移运算就是向右移动

21的二进制是10101
右移就是将他二进制整个向右移动
21>>1就是21的二进制10101向右移动1位:1010 = 10
10>>1就是42的二进制1010向右移动1位:101 = 5
21>>2就是21的二进制10101向右移动2位:101 = 5

  • 右移运算就是将整个二进制向右移动几位,减少的位置就减少了,相当于从后面砍了几位
  • 右移运算相当于除以2,所以…..

^异或操作

  • 异或操作:相同为0,不同为1
    21:10101
    12:01100
    =:11001 = 25

组合操作

判断eof

c语言编程中多行输入通常用scanf(…)!=EOF来判定
其实在c语言源码中EOF的值是-1,所以上面那句话等同于scanf(…)!=-1
而-1的二进制是32个1,具体看负数运算,所以32个1取反就是32个0,等于0
所以while(scanf(…)!=EOF)可以改写成while(~scanf(…)!=0),即while(~scanf(…)){…}

将某一位设置成某个数

将n的第i(从零开始)位设置为1

1
2
3
4
int set1(int n,int i){
n=n|(1<<i);
return n;
}

1<< i是让第i位为1,然后1或上任何数都是1,其他位上都是0,0或上任何数都让原数字保持不变

将n的第i(从零开始)位设置为0

1
2
3
4
int set0(int n,int i){
n =n&(~(1<<i));
return n;
}

~ (1<< i)操作让第i位为0,其他位为1,1与任何数都是任何数,0与任何数都是0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
int set1(int n,int i){
n=n|(1<<i);
return n;
}
int set0(int n,int i){
n =n&(~(1<<i));
return n;
}
int main(){
int a = 5;//二进制是101
printf("%d\n",set1(a,1));//将第一位设置为1,即111为7
printf("%d\n",set1(a,2));//将第2位设置为1,因为第二位本来就是1,所以没变,即101为5

printf("%d\n",set0(a,0));//将第0位设置为0,即100为4
printf("%d\n",set0(a,1));//将第一位设置为0,没变,即101为5
return 0;
}