总体遵循由特点推作用的原则
位运算是指整型或字符串型数据,将运算的对象看作二进制的串,按照位完成指定的运算。
一、前提知识补充(以下所有事例采用1字节即8位二进制数表示,因为只取低位无法看出变化)
注:先介绍原码、反码、补码,再介绍有符号无符号
1.原码反码补码
(1)二进制原码:
1->0000 0001
2->0000 0010
4->0000 0100
即每次进位不再是逢十进位,而是逢二进位,数的值不变,只是进位方式改变了,例如十进制中9+1需要进位,而二进制中1+1就需要进位。八进制、十六进制(十用A表示,十六用F表示)同理
(2)反码
符号位不变,其余按位取反,下文会讲到符号位
例如:
无符号1->0000 0001(原)->1111 1110(反)
有符号1->0000 0001(原)->0111 1110(反)
有符号2->0000 0010(原)->0111 1101(反)
无符号4->0000 0100(原)->1111 1011(反)
(3)补码
正数补码为原码
负数符号位不变,各位取反再加1
例如:
+1->0000 0001(原)->0111 1110(反)->0111 1111(补)
-1->1111 1111(原)->1000 0000(反)->1000 0001(补)
-2->1000 0010(原)->1111 1101(反)->1111 1110(补)
2.有符号无符号数及与原码反码补码的关系(以八位二进制码为例)
(1)无符号数所有位均为数值位
(2)有符号数首位为符号位,其余位为数值位
(3)是否是有符号数取决于定义而非数码
(4)负数的表示并非简单的改变符号位,其原因是如果只改变符号位不满足负数的大小关系
例如:如果按照改变符号位的方式
-1->1000 0001
-2->1000 0010
那么在计算机看来码1000 0010显然是大于1000 0001的,因此,根据大小关系,将1000 0000至1111 1111作为-128至-1的原码,而0000 0000至0111 1111作为0至127的原码,如下图1所示,这时我们会看到如下图2所示的对应关系,因为在正负数的表示中最容易想到的是反码,而反码所对应的数值与应该对应的数值又相差1,故而产生补码这一概念,通过反码加一的方式如图3即可方便的由一个数表示其负数。
二、各位运算解析
1.&运算
真值表:
0 | 1 | |
0 | 0 | 0 |
1 | 0 | 1 |
由真值表可知,&运算的特点为:
(1)同一位数值均为1时结果为1
(2)其余情况均为零
故其用途为:
(1)取出某位的值,工具串中:该位为1,其余为0
(2)清零,工具串中:所有位均为0
(3)可以通过与1与判断最低位是否为0,进而判断是否为偶数
#include<iostream>
using namespace std;
int main()
{
int a;
cin>>a;
int b=a&1;
if(b) cout<<"a是奇数"<<endl;
else cout<<"b是偶数"<<endl;
return 0;
}
2.|运算
真值表:
0 | 1 | |
0 | 0 | 1 |
1 | 1 | 1 |
由真值表可知,|运算的特点为:
(1)全0为0
(2)有1为1
故其用途为:
(1)无
(2)对数的某个位置置1
(3)可以通过与1或判断一个数是奇数还是偶数
例如:
#include<iostream>
using namespace std;
int main()
{
int a;
cin>>a;
int b=a|1;
if(a==b) cout<<"a是偶数"<<endl;
else cout<<"a是奇数"<<endl;
return 0;
}
3.~运算及!运算
真值表如下:
~ | ! | |
0 | 1 | 1 |
1 | 0 | 0 |
二者区别:
~运算是位运算,按位取反
!运算是基于bool值的取反,其只有两种取值即true(也即1)和false(也即0),故非零数(正数及负数)取!为0,0取!为1
4.^运算(异或运算)
其真值表如下:
0 | 1 | |
0 | 0 | 1 |
1 | 1 | 0 |
其特点为:
(1)0与0、1运算结果不变
(2)1与0、1运算结果相反
故其作用为:
(1)用于保留原值
(2)使特定位置反转,即工具串特定位置为1