信息学奥赛初赛天天练-15-阅读程序-深入解析二进制原码、反码、补码,位运算技巧,以及lowbit的神奇应用

news2024/11/23 16:33:07

更多资源请关注纽扣编程微信公众号
在这里插入图片描述

1 2021 CSP-J 阅读程序1

阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填 √,错误填×;除特 殊说明外,判断题 1.5 分,选择题 3 分)

源码

#include<stdio.h>
using namespace std;
 
int n;
int a[1000];

int f(int x)//计算二进制1中1的个数
{
	int ret = 0;
    /*
    2 对应二进制 10 ,包含1个1
    10&1=0 ret累加1次退出循环
    3对应二进制101,包含2个1
    101 & 100=100
    100&011=0 ret累加2次退出循环
    */
	for(;x;x&=x-1) ret++;
	return ret;
}
/*
  lowbit 是将 x 转化成二进制数之后,只保留最低位(从右往左数,第一位)的1及其后面的0,截断前面的内容,然后再转成10进制数
  lowbit(8)=8//8对应二进制为:1000 取最右边的1及后面3个0
  lowbit(12)=4//12对应二进制位:1100 取最右边的1及后面3个0
  lowbit(5)=1//5对应二进制为 101 取最右边1及其后面的0
 */
int g(int x)
{
	return x & -x;
}

int main()
{
	scanf("%d",&n);
	for (int i=0;i<n;i++) scanf("%d",&a[i]);
	for(int i=0;i<n;i++)
		printf("%d ",f(a[i])+g(a[i]));
	printf("\n");
	return 0;
}

判断题

1 输入的n等于1001时,程序不会发生下标越界( F )

2 输入的a[i]必须全为正整数,否则程序将陷入死循环( F )

3 当输入为“5 2 11 9 16 10” 时,输出“3 4 3 17 5” ( F )

4 当输入为“1 511998 ”时,输出为"18" ( T )

5 将原码中g函数的定义(13 -16行) 移到main函数的后面,程序可以正常编译运行( F )

单选题

6 当输入为"2 -65536 2147483647"时,输出为 ( B )

A. “65532 33”

B. “65552 32”

C. “65535 34”

D. “65554 33”

2 相关知识点

for 循环语句

重复执行一段代码,直到满足指定条件为止,使用三个表达式控制循环的初始化、退出条件和自变量更新,这3个表达式可以同时出现也可以部分出现

for (初始化表达式; 退出条件; 自变量更新) {
    // 循环体代码
}

示例代码

#include<bits/stdc++.h>
using namespace std;
/*
  for循环语句练习 
*/
int main(){
	//初始化表达式; 退出条件; 自变量更新 同时出现 
	for(int i=0;i<5;i++){
		cout<<i<<" ";
	}
	cout<<endl;
	//初始化表达式 提前定义 
	int i=0; 
	for(;i<5;i++){
		cout<<i<<" ";
	}
	cout<<endl;
	
	//初始化表达式 提前定义  退出条件在循环题 
	i=0; 
	for(;;i++){
		if(i>=5) break; 
		cout<<i<<" ";
	}
	
	cout<<endl;
	
	//初始化表达式 提前定义  退出条件在循环题 自变量在循环体 
	i=0; 
	for(;;){
		if(i>=5) break; 
		cout<<i<<" ";
		i++;
	}
	return 0;
}

原码、反码和补码

1) 机器数

一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用机器数的最高位存放符号,正数为0,负数为1

4  对应二进制 0000 0100
-4 对应二进制 1000 0100

2) 机器数真值

机器数第一位为符号位,所以机器数的形式值不等于真正的数值。所以,将带符号位的机器数对应的真正数值称为机器数的真值

0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

3) 原码

原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值

+2 的原码 0000 0010
-2 的原码 1000 0010

4) 反码

正数的反码是其本身

负数的反码是对原码进行符号位不变,其余各个位取反

+2 的原码 0000 0010   反码 0000 0010
-2 的原码 1000 0010   反码 1111 1101

5) 补码

正数的补码就是其本身

负数的反码是对反码+1

+2 的原码 0000 0010   反码 0000 0010  补码  0000 0010
-2 的原码 1000 0010   反码 1111 1101  补码  1111 1110

位运算

1) 取反运算(~)

是转换2进制后,每1位取反,0变1,1变0

示例代码

//按位取反 ~
#include<bits/stdc++.h>
using namespace std;

int main(){
	/*
	正数的原码,反码,补码都是相同
	4 对应二进制 
	0000 0100 
	按位取反
	1111 1011 计算机是以补码形式存在,需要转换成原码
	-1变成反码
	1111 1010
	按位取反变成原码
	1000 0101 
	第1位是符号位,所以结果是-5 
	*/ 
	int a=4;
	int b=~a;//转二进制补码后按位取反后再转成原码 
	cout<<b; //结果是-5 
	return 0;
}

2) 左移(<<)、右移(>>)

左移

左移1位,所有位都左移,末尾补0

右移

右移1位,所有位都右移,首尾补0

示例代码

//左移 <<  右移 >>
#include<bits/stdc++.h>
using namespace std;

int main(){
	int a=3;
	/*
	  3 对应二进制 
	  0000 0011 
	  左移1位,所有位都左移,末尾补0
	  0000 0110
	  此时对应二进制转十进制为6 
	*/
	int b=3<<1; 
	cout<<"b的值为:"<<b<<endl;//所以b的值为6 
	int c=8;
	/*
	  8 对应二进制 
	  0000 1000 
	  右移1位,所有位都右移,首尾补0
	  0000 0100
	  此时对应二进制转十进制为4 
	*/
	int d=c>>1;
	cout<<"d的值为:"<<d;//所以d的值为4
	return 0;
}

3) 按位与 (&)

运算规则,按位与的2个位同时为1时,结果为1,否则为0

示例代码

#include<bits/stdc++.h>
using namespace std;

int main(){
	int a=5;
	int b=6;
	/*
	5对应的二进制为
	0000 0101 
	6对应的二进制为
	0000 0110
	所以 5 & 6
	0000 0101
  & 0000 0110
  -------------
    0000 0100
    转对应10进制为4 
	*/ 
	int c=a&b;
	cout<<"c的值为:"<<c; //输出c的值为4 
	return 0;
}

4) 按位或 (|)

运算规则,按位或的2个位其中有1个为1,结果为1,否则为0

示例代码

#include<bits/stdc++.h>
using namespace std;

int main(){
	int a=5;
	int b=6;
	/*
	5对应的二进制为
	0000 0101 
	6对应的二进制为
	0000 0110
	所以 5 & 6
	0000 0101
  | 0000 0110
  -------------
    0000 0111
    转对应111进制为7 
	*/ 
	int c=a|b;
	cout<<"c的值为:"<<c; //输出c的值为7   
	return 0;
}

5) lowbit

lowbit(x)是将 x 转化成二进制数之后,只保留最低位(从右往左数,第一位)的1及其后面的0,截断前面的内容,然后再转成10进制数
例如

lowbit(8)=8//8对应二进制为:1000 取最右边的1及后面3个0
lowbit(12)=4//12对应二进制位:1100 取最右边的1及后面3个0
lowbit(5)=1//5对应二进制为 101 取最右边1及其后面的0

示例代码

#include<bits/stdc++.h>
using namespace std;

int g(int x){
	return x & -x;
}

int main(){
	int n=1;
	/*
	  1的补码
	  0000 0001
	  -1的原码
	  1000 0001
	  -1的反码
	  1111 1110
	  -1的补码
	  1111 1111
	  1 & -1
	  0000 0001
	 &1111 1111
	 -----------
	  0000 0001  
	*/ 
	cout<<"g(1)的值是: "<<g(n)<<endl;//输出1
	
	n=3;
	/*
	  3的补码
	  0000 0011
	  -1的原码
	  1000 0011
	  -1的反码
	  1111 1100
	  -1的补码
	  1111 1101
	  1 & -1
	  0000 0001
	 &1111 1101
	 -----------
	  0000 0001  
	*/ 
	cout<<"g(3)的值是: "<<g(n)<<endl;//输出1 
	
	n=8;
		/*
	  3的补码
	  0000 1000
	  -1的原码
	  1000 1000
	  -1的反码
	  1111 0111
	  -1的补码
	  1111 1000
	  1 & -1
	  0000 1000
	 &1111 1000
	 -----------
	  0000 1000  
	*/ 
	cout<<"g(8)的值是: "<<g(n)<<endl;//输出8 
	return 0;
}

6) x&=x-1

x&=x-1 去除二进制补码最后1个1

示例代码

#include<bits/stdc++.h>
using namespace std;
/*
  去除二进制补码最后一个1
  正数 
  9对应补码 0000 1001 
  8对应补码 0000 1000 
  x&=x-1;
  0000 1001 
& 0000 1000 
-------------
  0000 1000
结果为10进制的8
 负数
 -9
 原码  1000 1001
 反码  1111 0110
 补码  1111 0111
 x-1 -9-1=-10
 原码  1000 1010
 反码  1111 0101
 补码  1111 0110
 x&=x-1;
  1111 0111
& 1111 0110 
-------------
  1111 0110 
  比-9的补码 1111 0111少了末尾的1
  补码 1111 0110  对应反码 1111 0101 对应原码 1000 1010 对应十进制-10 
*/ 
int main(){
	int x=9;
	//去除二进制补码最后1个1 
	x&=x-1;
	cout<<x<<endl;//输出 8 
	
	x=-9;
	//去除二进制补码最后1个1 
	x&=x-1;
	cout<<x<<endl;//输出 -10 
	return 0;
}

3 思路分析

判断题

1 输入的n等于1001时,程序不会发生下标越界( F )

分析

a[1000]的下标范围为a[0] - a[999],所以a[1000]会导致越界

2 输入的a[i]必须全为正整数,否则程序将陷入死循环( F )

分析

负数不会进入死循环,负数计算机补码表示

例如 -3

在8位二进制中

原码 1000 0011

反码 1111 1100

补码 1111 1101

对应32位补码是

11111111111111111111111111111101

是31个1

3 当输入为“5 2 11 9 16 10” 时,输出“3 4 3 17 5” ( F )

分析

根据函数作用逐一输入上面5个数计算

输入数据后逐个计算,输出为3 4 3 17 4

f(2)+g(2)=1+2=3

f(2)+g(2)=3+1=4

f(2)+g(2)=2+1=3

f(2)+g(2)=1+16=17

f(2)+g(2)=2+2=4

4 当输入为“1 511998 ”时,输出为"18" ( T )

分析

511998 对应二进制 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0

f(2)+g(2)=16+2=18

5 将原码中g函数的定义(14 -16行) 移到main函数的后面,程序可以正常编译运行( F )

分析

main函数调用的函数必须在main函数前面定义,否则编译会出错

单选题

6 当输入为"2 -65536 2147483647"时,输出为 ( B )

A. “65532 33”

B. “65552 32”

C. “65535 34”

D. “65554 33”

分析

-65536

原码

00000000000000010000000000000000

反码

11111111111111101111111111111111

补码

11111111111111110000000000000000

所以f(-65536)+g(-65536)=16+65536=65552

2147483647 是2^32-1,31个1,最高位是符号位

正数的原码,反码,补码都相同

01111111111111111111111111111111

f(2147483647)+g(2147483647)=31 + 1=32

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1714766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

字符串编码转换

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 最早的字符串编码是美国标准信息交换码&#xff0c;即ASCII码。它仅对10个数字、26个大写英文字母、26个小写英文字母及一些其他符号进行了编码。ASC…

贪心(临项交换)+01背包,蓝桥云课 搬砖

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 0搬砖 - 蓝桥云课 (lanqiao.cn) 二、解题报告 1、思路分析 将物品按照w[i] v[i]升序排序然后跑01背包就是答案 下面证明&#xff1a;&#xff08;不要问怎么想到的&#xff0c;做题多了就能想到&#xff…

总负债20.79亿,银行借款在增加,经营所得现金在减少,累计亏损在增加,易点云披露其风险(四)

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 全文共二十五章&#xff0c;总计6万字。 由于篇幅所限&#xff0c;分为&#xff08;一&#xff09;到&#xff08;五&#xff09;篇发布。 本文为《负债20.79亿,银行借款在增加,经营所得现金在减少,易点云披露风险》&am…

力扣爆刷第146天之贪心算法五连刷

力扣爆刷第146天之贪心算法五连刷 文章目录 力扣爆刷第146天之贪心算法五连刷总结一、455. 分发饼干二、376. 摆动序列三、53. 最大子数组和四、122. 买卖股票的最佳时机 II五、5. 跳跃游戏 总结 贪心算法的本质就是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 一…

使用手机短信恢复软件,完成从新手到专家的进阶之路

由于各种原因&#xff0c;如误删、手机设备损坏等&#xff0c;我们可能会面临重要短信丢失的风险。现在市面上有许多手机短信恢复软件可以帮助我们解决这个问题&#xff0c;但从新手到专家的进阶之路并非一蹴而就的过程&#xff0c;它需要耐心、实践和不断地学习。以下是一篇关…

c++编程(15)——list的模拟实现

欢迎来到博主的专栏——c编程 博主ID&#xff1a;代码小豪 文章目录 前言list的数据结构list的默认构造尾插与尾删iterator插入和删除构造、析构、赋值copy构造initializer_list构造operator 析构函数 前言 受限于博主当前的技术水平&#xff0c;暂时还不能模拟实现出STL当中用…

HTTP报文

HTTP报文 报文流 HTTP报文是在HTTP引用程序之间发送的数据块&#xff0c;这些数据块以一种文本形式的元信息开头&#xff0c;这些信息描述了报文的内容和含义&#xff0c;后面跟着可选的数据部分&#xff0c;这些报文在客户端&#xff0c;服务器和代理之间流动。 报文流入源…

Java事务入门:从基础概念到初步实践

Java事务入门&#xff1a;从基础概念到初步实践 引言1. Java事务基础概念1.1 什么是事务&#xff1f;1.2 为什么需要事务&#xff1f; 2. Java事务管理2.1 JDBC 的事务管理2.2 Spring 事务管理2.2.1 Spring JDBC2.2.1.1 添加 Spring 配置2.2.1.2 添加业务代码并测试验证 2.2.2…

在做题中学习(62):矩阵区域和

1314. 矩阵区域和 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;二维前缀和 思路&#xff1a;读题画图才能理解意思&#xff1a;dun点点的是mat中的一个数&#xff0c;而要求的answer同位置的数 以点为中心上下左右延长 k 个单位所围成长方形的和。 因为最后answ…

拷贝构造、移动构造、拷贝赋值、移动赋值

最近在学习C的拷贝构造函数时发现一个问题&#xff1a;在函数中返回局部的类对象时&#xff0c;并没有调用拷贝构造函数。针对这个问题&#xff0c;查阅了一些资料&#xff0c;这里记录整理一下。 调用拷贝构造函数的三种情况&#xff1a; ① 用一个类去初始化另一个对象时&a…

PLC自动化行业的发展前景好吗?

第一先说plc的薪资&#xff1a; 整体的平均薪资还是非常可观的&#xff0c;在1.3w/月左右。 当然PLC是需要经验积累的&#xff0c;尤其需要拥有大型的系统设计经验&#xff0c;那将会在PLC以至于自动化行业都会吃的开。所以待遇是与自身的经验&#xff0c;能力&#xff0c;所在…

Java设计模式:享元模式实现高效对象共享与内存优化(十一)

码到三十五 &#xff1a; 个人主页 目录 一、引言二、享元设计模式的概念1. 对象状态的划分2. 共享机制 三、享元设计模式的组成四、享元设计模式的工作原理五、享元模式的使用六、享元设计模式的优点和适用场景结语 [参见]&#xff1a; Java设计模式&#xff1a;核心概述&…

GDPU Java 天码行空13

&#xff08;一&#xff09;实验目的 1、掌握JAVA中与网络程序开发相关的知识点&#xff1b; 2、理解并掌握网络编程开发思想及方法&#xff1b; 3、熟悉项目开发的分包方法和依据&#xff1b; 4、实现聊天室中客服端和服务器端的实现方法&#xff1b; 5、熟悉多线程程序开发方…

第五届武汉纺织大学ACM程序设计竞赛 个人题解(待补完)

前言&#xff1a; 上周周日教练要求打的一场重现赛&#xff0c;时长五个小时&#xff0c;题目难度还行&#xff0c;除了部分题目前我还写不出来之外&#xff0c;大部分题都写完或补完了&#xff0c;这边给出比赛链接和我的代码&#xff08;有些是队友的&#xff09;和题解。 正…

工作中有哪些超级好用的C/C++程序库?

视频和讲义发布在这里&#xff1a; B站链接

Spring框架温习

Spring Spring是一个全面的、企业应用开发一站式的解决方案&#xff0c;贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。 Spring 特点&#xff1a; 轻量级、控制反转、面向切面、容器、框架集合 Spring 核心组件&#xff1a; Spring 常用模块&…

Leecode热题100---二分查找--4:寻找两个正序数组的中位数

题目&#xff1a; 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 解法1、暴力解法&#xff08;归并&#xff09; 思路&#xff1a; 合并 nums1&#xff0c;nums2 为第三个数组 排序第三个数…

亚马逊VC账号产品热销,在美国哪些智能小家电产品最好卖?

亚马逊VC账号产品在美国市场的热销&#xff0c;反映了消费者对于特定智能小家电产品的强烈需求。智能小家电产品因其实用性、便捷性和科技感&#xff0c;近年来在美国市场备受追捧。 以下是一些在亚马逊VC账号上热销的智能小家电产品&#xff1a; 智能扫地机器人 这类产品在美…

【传知代码】自监督高效图像去噪(论文复现)

前言&#xff1a;在数字化时代&#xff0c;图像已成为我们生活、工作和学习的重要组成部分。然而&#xff0c;随着图像获取方式的多样化&#xff0c;图像质量问题也逐渐凸显出来。噪声&#xff0c;作为影响图像质量的关键因素之一&#xff0c;不仅会降低图像的视觉效果&#xf…

STM32读写内部FLASH读取芯片id

文章目录 读写内部Flash接线程序编写测试效果补充 读取芯片id代码编写 读写内部Flash 接线 程序编写 首先使用ThisFlash.c来写入flash的基本操作&#xff0c;写入、读取、擦除&#xff0c;然后使用Store.c配合数组来进行主存与flash的交互 ThisFlash.c #include "stm32…