当前位置: 首页 > article >正文

NO.36十六届蓝桥杯备战|位运算和操作符属性|进制转换|原码反码补码|左移|右移|按位与|按位或|按位异或|按位取反(C++)

操作符的分类

分类操作符
算术操作符+、-、*、/、%
移位操作符<<、>>
位操作符&、|、^
赋值操作符=、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=
单⽬操作符!、++、–、&、*、+、-、~、sizeof、(类型)
关系操作符>、>=、<、<=、==、!=
逻辑操作符&&、|
条件操作符? :
下标引⽤[]
函数调⽤()

⼆进制和进制转换

15 的 2 进制:1111  
15 的 8 进制:17  
15 的 10 进制:15  
15 的 16 进制:F

//16进制的数值之前写:0x  
//8进制的数值之前写:0
⼆进制

⾸先我们还是得从 10 进制讲起,其实 10 进制是我们⽣活中经常使⽤的,我们已经形成了很多常识:
• 10 进制中满 10 进 1
• 10 进制的数字是由 0~9 的数字组成的
其实⼆进制也是⼀样的
• 2 进制中满 2 进 1
• 2 进制的数字是由 0~1 的数字组成的
那么 1101 就是⼆进制的数字了。

2进制转10进制

其实 10 进制的 123 表⽰的值是⼀百⼆⼗三,为什么是这个值呢?其实 10 进制的每⼀位是有权重的, 10 进制的数字从右向左是个位、⼗位、百位…,分别每⼀位的权重是 1 0 0 , 1 0 1 , 1 0 2 … 10^0,10^1,10^2\dots 100,101,102

百位十位个位
10进制的位123
权重10^210^110^0
权重值100101
求值1*1002*103*1123

2 进制和 10 进制是类似的,只不过 2 进制的每⼀位的权重,从右向左是 2 0 , 2 1 , 2 2 … 2^0,2^1,2^2\dots 20,21,22
1101

2进制的位1101
权重2^32^22^12^0
权重值8421
求值1*81*40*21*113

8进制数转10进制数,⽅法类似,只是权重是 8 0 8^0 80 开始,然后依次是: 8 0 , 8 1 , 8 2 … 8^0,8^1,8^2\dots 80,81,82
16进制数转10进制数,⽅法类似,只是权重是 1 6 0 16^0 160 开始,然后依次是: 1 6 0 , 1 6 1 , 1 6 2 … 16^0,16^1,16^2\dots 160,161,162

10进制转2进制数字

![[Pasted image 20250311145342.png]]

2进制转8进制

8 进制的数字每⼀位是 0~7 中的数字, 0~7 中的数字,各⾃写成 2 进制,最多有 3 个 2 进制位就⾜够了,⽐如 7 的⼆进制是 111 ,所以在 2 进制转 8 进制数的时候,从 2 进制序列中右边低位开始向左每 3 个 2 进制位会换算⼀个 8 进制位,剩余不够 3 个 2 进制位的直接换算。
如: 2 进制的 01101011 ,换成 8 进制: 0153 , 0 开头的数字,会被当做 8 进制
8进制数转换2进制数是相关的过程,每⼀个8进制位转换成3个2进制位就⾏

2进制转16进制

16 进制的数字每⼀位是 0~9 , a~f 的, 0~9 , a~f 的数字,各⾃写成 2 进制,最多有 4 个 2 进制位就⾜够了,⽐如 f 的⼆进制是 1111 ,所以在 2 进制转 16 进制数的时候,从 2 进制序列中右边低位开始向左每 4 个 2 进制位会换算⼀个 16 进制位,剩余不够 4 个⼆进制位的直接换算。
如: 2 进制的 01101011 ,换成 16 进制: 0x6b , 16 进制表⽰的时候前⾯加 0x 。
![[Pasted image 20250311145539.png]]

16进制数转换2进制数是相关的过程,每⼀个16进制位转换成3个2进制位就⾏

原码、反码、补码

其实说到 2 进制,在计算机内部,数值是以 2 进制的形式来进⾏表⽰和存储。后⾯要讲解的位运算的操作符就是针对整数的⼆进制来进⾏运算的

移位运算符:>> <<  
位运算符 : & | ^

整数的 2 进制表⽰⽅法有三种,即原码、反码和补码;整数分为有符号整数(signed)和⽆符号整数(unsigned)。

有符号整数的原码、反码和补码的⼆进制表⽰中均由符号位和数值位两部分组成, 2 进制序列中,最⾼位的 1 位是被当做符号位,剩余的都是数值位,符号位都是⽤ 0 表⽰“正”,⽤ 1 表⽰“负”。
正整数的原、反、补码都相同。
负整数的三种表⽰⽅法各不相同,需要计算。
![[Pasted image 20250311145859.png]]

原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码 +1 就得到补码。
由补码得到原码也是可以使⽤:取反, +1 的操作。

int a = -10;  
原码:10000000 00000000 00000000 00001010  
反码:11111111 11111111 11111111 11110101  
补码:11111111 11111111 11111111 11110110  
int a = 10;  
原码:10000000 00000000 00000000 00001010  
反码:10000000 00000000 00000000 00001010  
补码:10000000 00000000 00000000 00001010

⽆符号整数的三种 2 进制表⽰相同,没有符号位,每⼀位都是数值位。
![[Pasted image 20250311150046.png]]

整数在内存中是以补码的形式存储的,整数在参与位运算的时候,也都是使⽤内存中的补码进⾏计算的,计算的产⽣的结果也是补码,需要转换成原码才是真实值。

在计算机系统中,整数的数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

练习

B3619 10 进制转 x 进制 - 洛谷
#include <bits/stdc++.h>
using namespace std;

string s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

void n_to_x(int n, int x)
{
    if (n >= x)
        n_to_x(n / x, x);
    
    cout << s[n % x];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, x;
    cin >> n >> x;
    n_to_x(n, x);
    
    return 0;
}
B3620 x 进制转 10 进制 - 洛谷
#include <bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int x;
    string s;
    cin >> x >> s;
    size_t n = s.size();
    int j = 0;
    int sum = 0;
    for (int i = n-1; i >= 0; i--)
    {
        if(s[i] <= '9')
            sum += (s[i] - '0') * pow(x, j);
        else
            sum += (s[i] - 'A' + 10) * pow(x, j);
        j++;
    }
    cout << sum << endl;
    
    return 0;
}
#include <bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int x;
    string s;
    cin >> x >> s;
    int ret = stoi(s, NULL, x);
    cout << ret << endl;
    return 0;
}
P1143 进制转换 - 洛谷
#include <bits/stdc++.h>
using namespace std;

string x = "0123456789ABCDEF";
void n_to_m(int t, int m)
{
    if (t >= m)
        n_to_m(t / m, m);
    cout << x[t % m];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    string s;
    cin >> n >> s >> m;
    int t = stoi(s, NULL, n);
    n_to_m(t, m);
    
    return 0;
}

位运算操作符

<< //左移操作符  
>> //右移操作符  
& //按位与操作符
| //按位或操作符
^ //按位异或操作符
~ //按位取反操作符
左移操作符

左移操作符是双⽬操作符,形式如下:

int num = 10;  
num << i; //将num的⼆进制表⽰,左移i位
#include <iostream>  
using namespace std;  
int main()  
{  
	int num = 10;  
	int n = num << 1;  
	cout << "n = " << n << endl;  
	cout << "num = " << num << endl;  
	
	return 0;  
}

![[Pasted image 20250311165339.png]]

右移操作符

右移操作符是双⽬操作符,形式如下:

num >> i;//将num的⼆进制表⽰右移i位
#include <iostream>  
using namespace std;  
int main()  
{  
	int num = -1;  
	int n = num >> 1;  
	cout << "n = " << n << endl;  
	cout << "num = " << num << endl;  
	
	return 0;  
}

右移运算分两种:逻辑右移和算术右移,具体采⽤哪种右移⽅式取决于编译器,⼤部分的编译器采⽤的是算术右移。两种移位⽅式的规则如下:

  1. 逻辑右移:左边⽤ 0 填充,右边丢弃
  2. 算术右移:左边⽤原该值的符号位填充,右边丢弃
    逻辑右移
    ![[Pasted image 20250311165653.png]]

算数右移
![[Pasted image 20250311165733.png]]

对于移位运算符,不要移动负数位,这个是标准未定义的

按位与操作符

按位与操作符是双⽬操作符,形式如下:

a & b; //a和b按位与运算

对两个数的对应⼆进制位进⾏与运算,只有对应的两个⼆进位都为 1 时,结果才为 1

#include <iostream>  
using namespace std;  
int main()  
{  
	int a = -5;  
	int b = 7;  
	int c = a & b;  
	cout << c << endl;  
	
	return 0;  
}

![[Pasted image 20250311165930.png]]

-5的原码: 10000000 00000000 00000000 00000101
-5的反码: 11111111 11111111 11111111 11111010
-5的补码: 11111111 11111111 11111111 11111011
7的补码:00000000 00000000 00000000 00000111

-5的补码和7的补码按位与运算如下
![[Pasted image 20250311170006.png]]

计算得到⼆进制是: 00000000 00000000 00000000 00000011 ,这个⼆进制序列当作补码时,且最⾼是 1 ,说明是正数,所以原码也是这个,所以最终 c 为 3

按位或操作符

按位或操作符是双⽬操作符,形式如下

a | b; //a和b按位或运算

对两个数的对应⼆进制位进⾏或运算,对应的两个⼆进位只要有 1 ,或结果就为 1
![[Pasted image 20250311170200.png]]

#include <iostream>  
using namespace std;  
int main()  
{  
	int a = -5;  
	int b = 7;  
	int c = a | b;  
	cout << c << endl;  
	
	return 0;  
}

![[Pasted image 20250311170222.png]]

-5的原码: 10000000 00000000 00000000 00000101
-5的反码: 11111111 11111111 11111111 11111010
-5的补码: 11111111 11111111 11111111 11111011
7的补码:00000000 00000000 00000000 00000111
-5的补码和7的补码按位或运算如下:
![[Pasted image 20250311170250.png]]

计算得到⼆进制是: 11111111 11111111 11111111 11111111 ,这个⼆进制序列当作补码
时,且最⾼是 1 ,说明是负数,求的原码为: 10000000 00000000 00000000 00000001 ,所以最终c为 -1 。

按位异或操作符

按位异或操作符是双⽬操作符,形式如下:

a ^ b; //a和b按位异或运算

对两个数的对应⼆进制位进⾏异或运算,对应的两个⼆进位相同则为 0 ,相异则为 1
![[Pasted image 20250311170641.png]]

#include <iostream>  
using namespace std;  
int main()  
{  
	int a = -5;  
	int b = 7;  
	int c = a ^ b;  
	cout << c << endl;  
	
	return 0;  
}

![[Pasted image 20250311170702.png]]

-5的原码: 10000000 00000000 00000000 00000101
-5的反码: 11111111 11111111 11111111 11111010
-5的补码: 11111111 11111111 11111111 11111011
7的补码:00000000 00000000 00000000 00000111
-5的补码和7的补码按位异或运算如下:
![[Pasted image 20250311170726.png]]

计算得到⼆进制是: 11111111 11111111 11111111 11111100 ,这个⼆进制序列当作补码
时,且最⾼是 1 ,说明是负数,求的原码为: 10000000 00000000 00000000 00000100 ,所以最终 c 为 -4

按位取反操作符

按位取反操作符是单⽬操作符,形式如下:

~a; //对a的⼆进制位按位取反

对操作数的⼆进制位进⾏按位取反运算, 2 进制是 0 的变成 1 ,是 1 的变成 0

#include <iostream>  
using namespace std;  
int main()  
{  
	int a = -5;  
	int b = ~a;  
	cout << b << endl;  
	
	return 0;  
}

![[Pasted image 20250311170829.png]]

-5的原码: 10000000 00000000 00000000 00000101
-5的反码: 11111111 11111111 11111111 11111010
-5的补码: 11111111 11111111 11111111 11111011
对-5的补码按位取反运算如下:

计算得到⼆进制是: 00000000 00000000 00000000 00000100 ,这个⼆进制序列当作补码时,且最⾼是 0 ,说明是正数,所以原码也是这个,最终 c 为 -4


http://www.kler.cn/a/581880.html

相关文章:

  • 帕金森病如何 “偷走” 患者的正常生活?
  • HttpMediaTypeNotAcceptableException报错解决,状态码显示为406
  • 3dsmax烘焙光照贴图然后在unity中使用
  • shell脚本一键更新部署docker中服务
  • 《深度学习进阶》第7集:深度实战 通过训练一个智能体玩游戏 来洞察 强化学习(RL)与决策系统
  • 操作系统与网络基础:掌握网络安全的核心技能
  • 基于django+pytorch(Faster R-CNN)的钢材缺陷识别系统
  • HTML 列表详解
  • 【前端】【webpack-dev-server】proxy跨域代理
  • C++全栈聊天项目(2) 单例模式封装Http管理者
  • mac本地部署Qwq-32b记录
  • 【Spring】基础/体系结构/核心模块
  • 计算机网络开发(3)——端口复用、I\O多路复用
  • CSS 中 margin 的margin塌陷问题
  • 图论·拓扑排序
  • ClickHouse 数据倾斜实战:案例分析与优化技巧
  • 【Go】Go zap 日志模块
  • vue3中事件总线
  • 蓝桥杯备考:背包初次了解以及01背包
  • STM32-SPI通信外设