【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题

题目:求一个整数存储在内存中的二进制中的1的个数

目录

法一:取模与取余

法二:按位与和移位操作符

法三:利用算法去掉二进制中最右边的1

课外练习1:用位运算判断一个数是否是2的次方数 

课外练习2:编写代码将13二进制序列的第5位修改为1,然后再改回0


法一:取模与取余

 分析:

        数据在内存中以补码形式存储

        题目要求我们求一个数在内存中二进制中1的个数,从这里可以想到,我们需要定义一个变量count来计数,再得到二进制的每一位,并且再判断它是否为1,这道题就差不多解决了。但问题就是如何得到二进制的每一位?我们知道二进制的每一位要么是0要么是1,因此求二进制中1的个数,只需%2,看得到的余数是不是1,如果是1,count++,之后/2使得这个二进制去掉最后一位,如此循环往复,直到该数字为0,count的值就是1的个数。

#include <stdio.h>
int main()
{
	int num = 10;//00....01001
	scanf("%d", &num);
	int count = 0; //计数
	while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}
	printf("二进制中1的个数 = %d\n", count);
	return 0;
}

运行结果: 

从运行结果来看,-1的输出是错的,因此,这种实现方法肯定有问题。

那是为什么呢?

现在,我们来找找问题:

输入-1时,由于num为负数,所以num/2的值为向下取整的结果,即-1/2=-1,此时num的值仍为-1,因此while循环不会结束,导致程序出现死循环。同时,由于num的值一直为负数,所以num % 2 的结果始终为0,导致count的值一直为0。

因此这个问题是由于-1是负数,那我们把num类型定为无符号整型,会整型会怎样呢?

      修改后: 

#include <stdio.h>
int main()
{
    unsigned int num = 10;
    scanf("%u", &num);
    int count = 0; //计数
    while (num)
    {
        if (num % 2 == 1)
            count++;
        num = num / 2;
    }
    printf("二进制中1的个数 = %d\n", count);
    return 0;
}

 运行结果:

答案正确。

这是因为将输入的无符号整数 num 强制转换为有符号整数 int 类型,导致输入的负数被解释为一个很大的正整数。当输入-1时,它被当作非常大的正整数(4294967295)来处理,然后计算其补码二进制表示中 1 的个数,最终输出结果为 32。 

   法二:按位与和移位操作符

     这里先上代码,再分析

int main()
{
	int num = -1;
    scanf("%d", &num);
	int i = 0;
	int count = 0; //计数
	for (i = 0; i < 32; i++)
	{
		if (num & (1 << i))
			count++;
	}
	printf("⼆进制中1的个数 = %d\n", count);
	return 0;
}

    我们以-1来分析:

  • 数据在计算机中的存储形式是补码,而程序打印数据是以二进制的原码形式转换成十进制

  • -1的原码:10000000000000000000000000000001

    -1的反码:11111111111111111111111111111110

    -1的补码:11111111111111111111111111111111

  • (1 << i)   :1向左移动 i 位

当 i 为0时,结果为0000......01;

当 i 为1时,1向左移动一位,最左边丢掉一位,右边补一个0,结果为0000.....10;

当 i 为2时,1左移两位,丢掉最左边两位,在最右边补两个0,结果为0000.......100

因此(1<<i)产生的效果就是让数字1存储在内存中唯一的二进制位 1 移动 i 位

  • &按位与运算符:对应二进制位有0,则0
  • num & (1 << i):当 i 为0 时,1111....11& 0000....01结果为0000.....01,即1,为真,count++;

        当 i 为1时,1111......11&0000....10结果为0000....10,即2,为真,count++;

        .

        .

        .

        最终结果为32

   法三:利用算法去掉二进制中最右边的1

        一个数字与上这个数字减一的数,该数二进制最右边的1必然会消除掉,以此类推,从右往左,每一次进行按位与操作,都会取消掉一个1,直到该数字变为0,跳出循环,就得到了该数字二进制中1的个数。

以3(0000...0011)为例:

num:             0000...0011 —>       3

num - 1:          0000...0010 —>       2   

num = 3 & 2:   0000...0010  —>      2

num - 1:          0000...0001  —>      1

num = 2 & 1:   0000...0000 —>        0

跳出循环

#include <stdio.h>
int main()
{
	int num = -1;
    scanf("%d",&num);
	int i = 0;
	int count = 0; //计数
	while (num)
	{
		count++;
		num = num & (num - 1);
	}
	printf("⼆进制中1的个数 = %d\n", count);
	return 0;
}

        已经到这里了,来道课外练习巩固吧!

课外练习1:用位运算判断一个数是否是2的次方数 

        先自己思考动动手,再来看把!

#include <stdio.h>
int isPowerOfTwo(int n) 
{
	if (n <= 0) 
	{
		return 0;
	}
	return (n & (n - 1)) == 0;
}
int main()
{
	int num;
	scanf("%d", &num);
	if (isPowerOfTwo(num))
	{
		printf("%d 是2的次方数。\n", num);
	}
	else 
	{
		printf("%d 不是2的次方数。\n", num);
	}
	return 0;
}

简单分析:一个数如果是2的次方数,则它的二进制表示中只有一位是1,例如:1、2、4、8、16等。 

课外练习2:编写代码将13二进制序列的第5位修改为1,然后再改回0

13的2进制序列: 00000000000000000000000000001101
将第5位置为1后:00000000000000000000000000011101
将第5位再置为0:00000000000000000000000000001101

同样的,还是要先自己练习了,再来看!

二进制序列的第n位修改为1的公式:a = a | (1 << n - 1)

分析:以a = a | (1 << n - 1)为例

          设 a = 2         // 0000...0010

  • (1 << i)   :1向左移动 i 位

        当 n为1时,结果为0000......01;

        当 n 为2时,1向左移动一位,最左边丢掉一位,右边补一个0,结果为0000.....10;

        当 n 为3时,1左移两位,丢掉最左边两位,在最右边补两个0,结果为0000.......100

        因此(1<<n - 1)产生的效果就是让数字1存储在内存中唯一的二进制位 1 移动 n - 1 位

  • | 按位或运算符:对应二进制位有1,则1
  • a |(1 << n - 1):设n为3时,0000....010 | 0000....100结果为 0000....110,这样就把第i位改为1了

以此类推,二进制序列的第n位修改为0的公式:a = a & ~ (1 << n - 1)

代码:

#include <stdio.h>
int main()
{
	int a = 13;
	a = a | (1 << 4);
	printf("a = %d\n", a);
	a = a & ~(1 << 4);
	printf("a = %d\n", a);
	return 0;
}

 运行结果:

只有一点小小归纳,希望能帮到大家!

如果大家发现知识点错误的话,请帮忙指出,十分感谢!!

也请大家帮忙点赞、评论,这将督促我前行,大家一起加油!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Word自动化办公】使用python-docx对Word进行操作

目录 一、环境安装 二、文档各组成结构获取 2.1 组成结构讲解 2.2 段落run对象的切分标准 三、获取整篇文档内容 四、写入指定样式的数据 4.1 通过add_paragraph与add_run参数添加样式 4.2 单独设置文本样式 五、添加标题 六、换行符&换页符 七、添加图片数据 …

64位下使用回调函数实现监控(下)

线程监控&保护 PsSetCreateThreadNotifyRoutine 线程监控使用到的API相对于进程监控简单&#xff0c;使用到PsSetCreateThreadNotifyRoutine&#xff0c;而这个值并不能像进程操作的API一样进行操作&#xff0c;这里我们首先先使用这个API来进行线程的监控 NotifyRoutine…

wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载材质文件Mtl 中的纹理图片最简实例(十六)

文章目录 前言一、3d 立方体 model 属性相关文件1. cube.obj2. cube.Mtl3. 纹理图片 cordeBouee4.jpg二、代码实例1. 依赖库和头文件1.1 assimp1.2 stb_image.h2. egl_wayland_obj_cube.cpp3. Matrix.h 和 Matrix.cpp4. xdg-shell-client-protocol.h 和 xdg-shell-protocol.c5.…

部署Zabbix Agents添加使能监测服务器_Linux平台_Yum源/Archive多模式

Linux平台 一、从yum源脚本安装部署Zabbix-Agent,添加Linux Servers/PC 概述 Zabbix 主要有以下几个组件组成: Zabbix Server:Zabbix 服务端,Zabbix的核心组件,它负责接收监控数据并触发告警,还负责将监控数据持久化到数据库中。 Zabbix Agent:Zabbix客户端,部署在被监…

使用Python抓取抖音直播间数据的简易指南【第152篇—抓取数据】

使用Python抓取抖音直播间数据的简易指南 说明&#xff1a;本文已脱敏&#xff0c;隐去地址。 在这个数字化时代&#xff0c;直播已经成为了人们获取信息、娱乐和社交的重要方式之一。抖音作为全球知名的短视频平台&#xff0c;其直播功能也备受用户青睐。本文将介绍如何使用Py…

生成式人工智能

生成式人工智能&#xff08;Generative AI&#xff09;是人工智能的一个分支&#xff0c;专注于创建或生成新的内容&#xff0c;包括文本、图像、音频和视频等。与识别或分类等任务不同&#xff0c;生成式AI的目标是创造出在某种程度上新颖且具有实际意义的输出。这种类型的AI系…

Vue3 组件之间的通信

一、父子通信 ① props 父传子&#xff08;这种传值方法是只读的&#xff0c;不可以进行修改。&#xff09; 父组件props.vue中 <template><h2>props:我是父组件</h2><hr><props-child msg"我是静态的数据" :num"num" :obj&…

VTK9.2.0+Qt5.14.0 绘制点云

背景 为了显示结构光重建后的点云&#xff0c;开发QT5.14.0VTK9.2.0的上位机软件&#xff0c;用于对结构光3D相机进行控制&#xff0c;并接收传输回来的3D数据&#xff0c;显示在窗口中。 配置QT和VTK VTK9.2.0下载源码&#xff0c;用Cmake编译&#xff0c;编译好的VTK9.2.0…

GitHub gpg体验

文档 实践 生成新 GPG 密钥 gpg --full-generate-key查看本地GPG列表 gpg --list-keys关联GPG公钥与Github账户 gpg --armor --export {key_id}GPG私钥对Git commit进行签名 git config --local user.signingkey {key_id} # git config --global user.signingkey {key_id} git…

30V转5V 1A 30降压12V 1A DCDC低电压恒压IC 车充芯片-H4110

30V转5V和30V转12V的DCDC低电压恒压IC&#xff08;也称为降压恒压芯片或车充芯片&#xff09;工作原理如下&#xff1a; 输入电压识别&#xff1a;芯片首先识别输入的30V电压&#xff0c;并准备进行转换。 PWM控制&#xff1a;芯片内部的控制逻辑生成PWM信号。这个信号用于控制…

JVM—内存可见性

什么是可见性 可见性&#xff1a;一个线程对共享变量值的修改,能够及时地被其他线程看到共享变量&#xff1a;如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JMM) Java内存模型(Java Memory Model)描述了Java程序中各种…

Qt教程 — 3.7 深入了解Qt 控件: Layouts部件

目录 2 如何使用Layouts部件 2.1 QBoxLayout组件-垂直或水平布局 2.2 QGridLayout组件-网格布局 2.3 QFormLayout组件-表单布局 在Qt中&#xff0c;布局管理器&#xff08;Layouts&#xff09;是用来管理窗口中控件位置和大小的重要工具。布局管理器可以确保窗口中的控件在…

BAAI 北京智源研究院

文章目录 关于 BAAI产品悟道大模型FlagOpen 大模型技术天演 生物智能九鼎 智算平台 关于 BAAI BAAI : Beijing Academy of Artificial Intelligence 北京智源研究院 官网&#xff1a;https://www.baai.ac.cnhf : https://huggingface.co/BAAI百度百科 https://baike.baidu.co…

物联网云组态是什么?部署物联网云组态有什么作用?

在信息化与工业化的深度融合进程中&#xff0c;物联网云组态以其独特的优势&#xff0c;正在成为企业数字化转型的重要工具。那么&#xff0c;物联网云组态究竟是什么呢&#xff1f;部署物联网云组态又能给企业带来哪些实质性的好处呢&#xff1f;今天&#xff0c;我们将围绕这…

2核4G服务器多少钱?阿里云价格30元起

阿里云2核4G服务器租用优惠价格&#xff0c;轻量2核4G服务器165元一年、u1服务器2核4G5M带宽199元一年、云服务器e实例30元3个月&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接如下图&#xff1a; 阿里云2核4G服务器优惠价格 轻量应用服务器2核2G4M带宽、60GB高效…

AI智能分析网关V4在养老院视频智能监控场景中的应用

随着科技的快速发展&#xff0c;智能监控技术已经广泛应用于各个领域&#xff0c;尤其在养老院这一特定场景中&#xff0c;智能监控方案更是发挥着不可或缺的作用。尤其是伴随着社会老龄化趋势的加剧&#xff0c;养老院的安全管理问题也日益凸显。为了确保老人的生活安全&#…

Ruby选择结构实战

文章目录 一、Ruby选择结构实战概述二、Ruby选择结构实战案例&#xff08;一&#xff09;闰年判断1、编写程序&#xff0c;实现功能2、程序的解释说明3、运行程序&#xff0c;查看结果 &#xff08;二&#xff09;求解一元二次方程1、编写程序&#xff0c;实现功能2、程序的解释…

界面控件DevExpress ASP.NET Ribbon组件 - 完美复刻Office 365体验!

无论用户是喜欢传统工具栏菜单外观、样式&#xff0c;还是想在下一个项目中复制Office 365 web UI&#xff0c;DevExpress ASP.NET都提供了所需要的工具&#xff0c;帮助用户打造更好的应用程序界面。 P.S&#xff1a;DevExpress ASP.NET Web Forms Controls拥有针对Web表单&a…

ky10.aarch64安装Jenkins

参考地址&#xff1a;《安装部署 Jenkins》 前言 有war包和rpm两种安装方式&#xff0c;如果是长期使用更加推荐rpm的安装方式&#xff0c;可以更好的管理Jenkins&#xff1b; 我此次安装jenkins主要用于测试和简单的个人使用&#xff0c;所以选择更轻便的war安装。 1 下载J…

如何用java使用es

添加依赖 如何连接es客户端 RestHighLevelClient 代表是高级客户端 其中hostname&#xff1a;es的服务器地址&#xff0c;prot端口号 &#xff0c;scheme&#xff1a;http还是https 如果不在使用es可以进行关闭&#xff0c;可以防止浪费一些资源 java如何创建索引&#xff1…