算法通关村十一关 | 位运算的规则

1.数字在计算机中的表示

  1. 机器数:一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是自带符号的,在计算机用一个数的最高位存放符号,整数为0,负数为1。比如,十进制中的数+3,计算机字长8位,转换成二进制就是00000011.如果是-3.就是10000011。两者都是机器数。

  2. 真值:因为机器数的第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数10000011,其实最高位1代表负,其真正数值是-3,而不是形式数值131(10000011转换成10进制等于131)。所以将带符号位的机器数对应的的真正数值称为机器数的真值。(0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = -000 0001 = -1)。

    计算机对机器数的表示进一步细化:原码,反码,补码。

  3. 原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值,比如如果是8位二进制:

    [+1]原 = 0000 0001

    [-1]原 = 1000 0001

    第一位是符号位所以8进制的取值范围是

    [1111 1111, 0111 1111] 即[-127 , 127]

  4. 反码的表示方法是:正数的反码是其本身,负数的反码在原码的基础上,符号位不变,其它位取反。

    [+1] = [0000 0001]原 = [0000 0001]反

    [-1] = [1000 0001]原 = [1111 1110]反

    可以发现一个反码表示的是负数,人脑无法直观的看出来它的数值,通常要将其转换成原码再计算。

    因为补码能保持加和减运算的统一,因此应用更广,其表示方法是:

    • 正数的补码就是其本身

    • 负数的补码是在反码的基础上加1

    对于负数,补码也需要转换成原码在计算其数值

    拓展为何会有原码、反码和补码?

    [+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补

    [-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补

    我们都知道计算机中只有加法,我们看个例子,计算十进制的表达式:1-1=0,看原码表示:

    1- 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [1000 0010]原 = -2

    结果不正确

    用反码计算:

    1- 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原

    = [0000 0001]反 + [1111 1110]反

    =[1111 1111]反 = [1000 0000] 原 =-0

    有点奇怪,0带符号没有意义

    用补码计算:

    1- 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原

    = [0000 0001]补 + [1111 1111]补

    =[0000 0000] 补+[0000 0000]原 = 0

    负0就不存在了,可以用[1000 0000] 表示-128。补码的表示范围就是[-128 - 127]

2.位运算规则

2.1与、或、异或和取反

  1. 与运算 & ,规则:对于每个二进制位,两个数都为1,结果才为1,否则结果为0.

    0 & 0 = 0

    0 & 1 = 0

    1 & 0 = 0

    1 & 1 = 1

  2. 或运算 | ,规则:对于每个二进制位,两个数都为0时,结果才为0,否则结果为1.

    0 | 0 = 0

    0 | 1 = 1

    1 | 0 = 1

    1 | 1 = 1

  3. 异或运算的符号价⊕(在代码中用^表示),相同为0,不同为1

    0 ⊕ 0 = 0

    0 ⊕ 1 = 1

    1 ⊕ 0 = 1

    1 ⊕ 1 = 0

  4. 取反运算符号 ~,运算规则,0变1,1变0,

2.2 移位运算

  1. 移位运算分为左移和右移,按照是否带符号可以分成算术运算和逻辑移位。

    原始:0000 0110 6

    右移一次:0000 0011 3 相当于除以2

    左移一次:0000 1100 12 相当于乘于2

  1. 左移运算的符号是<< ,左移运算时,将全部运算时,将全部二进制位向左移动若干位,高位丢弃,低位补0。对于左移运算,算术移位和逻辑移位是相同的。

  2. 右移运算的符号是>>,右移运算时,将全部的二进制位向右移动若干位,低位丢弃,高位的补位由算术移位或逻辑移位决定:

    • 算术移位时,高位补最高位,(负数最高位补1,正数补0)

    • 逻辑右移时,高位补0

    在计算机中,对于0和正数,算术移位和逻辑移位结果是相同的。负数的结果时不同的。

    对于C++,数据类型包含有符号和无符号类型。有符号类型右移为算术右移,无符号类型右移运算为逻辑右移。

    对于Java,不存在无符号类型,算术右移是>>,逻辑右移是>>>

2.3 移位运算与乘除法的关系

  1. 左移运算对应乘法关系。低位补0,将一个数左移k位,相当于这个数乘于2^k.

  2. 右移运算对应除法关系,将一个数右移k位,相当于这个数除以2^k.

    需要注意的是:

    • 左移无需考虑太多只需低位补0即可。

    • 对于负数和正数的右移对应的结果是不一致的,分为算术右移和逻辑右移。算法在出题的时候考虑到这一点,大部分会将数据限制在正数和0的情况 ,因此可以放心的左移或右移。

2.4 位运算技巧

位运算的性质有很多,有一些运算公式,

  • 幂等律:a&a=a, a | a = a (注意异或运算不满足幂等率)

  • 交换律:a & b = b & a, a| b = b | a, a ⊕ b = b ⊕ a

  • 结合律:( a & b) & c = a& ( b& c) ,(a | b) | c = a | ( b | c),(a ⊕ b) & c = a ⊕( b ⊕ c)

  • 分配律:(a & b) | c = ( a & c) & ( b & c) ,(a | b) & c = (a & b) | ( b& c) ,异或同理

  • 德摩根律:~(a & b)= ( ~a) | (~ b), ~(a | b) = (~a) & (~b)

  • 取反运算性质:-1 = ~0, -a = ~( a - 1)

  • 与运算性质:a & 0 = a, a& (~1) = a,a & (~a) = 0;

  • 或运算性质: a | 0 = a, a | ( ~ a) = -1 ;

  • 异或运算性质: a⊕0 = a, a⊕a = 0;

根据上面的性质可以得到很多的处理技巧,

  • a & (a - 1) 的结果位将a的二进制表示的最后一个1变为0;

  • (补码)a&(-a) 的结果为只保留a的二进制表示的最后一个,其余的1都变成0.

如何获取、设置、和更新某个位的数据,也有固定的套路。

  1. 获取

    该方法是将1左移i位,得到形如00010000的值,接着对这个值与num执行“位与”操作,从而将i位之外的所有位清零,最后检查该结果是否为零。不为零i位为1,否则i位位0。代码如下:

    boolean getBit(int num, int i) {

    return ((num & (1 << i))) != 0;

    }

  2. 设置(将某一位置设置为1)

    setBit先将1右移i位,得到形如00010000的值,接着对这个值和num执行“位或”操作,这样只会改变i位的数据。除i位外的位均为零,故不会影响num的其余位。代码如下:

    int setBIt(int num, int i) {

    return num | (i << i);

    }

  3. 清零(将某一位置设置为0)

    该方法与setBit方法相反,首先将1左移i位获得形如00010000的值,对这个值取反的到类似11101111的值,接着对该值和num执行“位与”,古不会影响到num的其余位,只会清零i位。代码如下:

    int clearBit(int num, int i) {

    int mask = ~(1 << i); return num & mask;

    }

  4. 更新

    这个方法是将setBit和clearBit合二为一,首先用11101111的值num的第i位清零,接着将待写入的值v左移i位,得到一个i位为v但其余为都为0的数。最后对之前的结果执行“位或”操作,v为1则num的i位更新为1,否则为0.代码如下:

    int updateBit(int num, int i, int v) {

    int mask = ~(1 << i); return (num & mask) | (v << i);

    }

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

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

相关文章

Linux下彻底卸载jenkins

文章目录 1、停服务进程2、查找安装目录3、删掉相关目录4、确认已完全删除 1、停服务进程 查看jenkins服务是否在运行&#xff0c;如果在运行&#xff0c;停掉 ps -ef|grep jenkins kill -9 XXX2、查找安装目录 find / -name "jenkins*"3、删掉相关目录 # 删掉相…

一文全懂!带你了解芯片“流片”!

一、流片是什么&#xff1f; 流片(tape-out)是指通过一系列工艺步骤在流水线上制造芯片&#xff0c;是集成电路设计的最后环节&#xff0c;也就是送交制造。 流片即为"试生产"&#xff0c;简单来说就是设计完电路以后&#xff0c;先生产几片几十片&#xff0c;供测试…

【SQL语句】SQL编写规范

简介 本文编写原因主要来于XC迁移过程中修改SQL语句时&#xff0c;发现大部分修改均源自于项目SQL编写不规范&#xff0c;以此文档做以总结。 注&#xff1a;此文档覆盖不甚全面&#xff0c;大体只围绕迁移遇到的修改而展开。 正文 1、【字段引号】 列名、表名如无特殊情况…

使用BeeWare实现iOS调用Python

1、准备工作 1.1、安装Python 1.2、设置虚拟环境 我们现在将创建一个虚拟环境——一个“沙盒”&#xff0c;如果我们将软件包安装到虚拟环境中&#xff0c;我们计算机上的任何其他Python项目将不会受到影响。如果我们把虚拟环境搞得一团糟&#xff0c;我们将能够简单地删除它…

C++入门:内联函数,auto,范围for循环,nullptr

目录 1.内联函数 1.1 概念 1.2 特性 1.3 内联函数与宏的区别 2.auto关键字(C11) 2.1 auto简介 2.2 auto的使用细则 2.3 auto不能推导的场景 3.基于范围的for循环(C11) 3.1 范围for的语法 3.2 范围for的使用方法 4.指针空值nullptr(C11) 4.1 C98中的指针空值 1.内联…

面试问题记录

1.多线程&#xff0c;线程池 1.如何创建线程 实现 Runnable 接口&#xff0c;重写run方法&#xff1b;实现 Callable 接口&#xff0c;重写call方法&#xff1b;继承 Thread 类&#xff0c;重写run方法。 2.基础线程机制 Executors&#xff1a;可以创建四种类型的线程池&am…

15.树与二叉树基础

目录 一. 树&#xff0c;基本术语 二. 二叉树 &#xff08;1&#xff09;二叉树 &#xff08;2&#xff09;满二叉树 &#xff08;3&#xff09;完全二叉树 三. 二叉树的性质 四. 二叉树的存储结构 &#xff08;1&#xff09;顺序存储结构 &#xff08;2&#xff09;链…

CSerialPort教程4.3.x (3) - CSerialPort在MFC中的使用

CSerialPort教程4.3.x (3) - CSerialPort在MFC中的使用 环境&#xff1a; 系统&#xff1a;windows 10 64位 编译器&#xff1a;Visual Studio 2008前言 CSerialPort项目是一个基于C/C的轻量级开源跨平台串口类库&#xff0c;可以轻松实现跨平台多操作系统的串口读写&#x…

C#__自定义类传输数据和前台线程和后台线程

// 前台线程和后台线程 // 默认情况下&#xff0c;用Thread类创建的线程是前台线程。线程池中的线程总是后台线程。 // 用Thread类创建线程的时候&#xff0c;可以设置IsBackground属性&#xff0c;表示一个后台线程。 // 前台线程在主函数运行结束后依旧执行&#xff0c;后台线…

golang的继承

golang中并没有继承以及oop&#xff0c;但是我们可以通过struct嵌套来完成这个操作。 定义struct 以下定义了一个Person结构体&#xff0c;这个结构体有Eat方法以及三个属性 type Person struct {Name stringAge uint16Phone string }func (recv *Person) Eat() {fmt.Prin…

01.Django入门

1.创建项目 1.1基于终端创建Django项目 打开终端进入文件路径&#xff08;打算将项目放在哪个目录&#xff0c;就进入哪个目录&#xff09; E:\learning\python\Django 执行命令创建项目 F:\Anaconda3\envs\pythonWeb\Scripts\django-admin.exe&#xff08;Django-admin.exe所…

微信支付-使用微信JSSDK完成微信支付

前言 使用微信JSSDK完成微信支付 一、安装weixin-js-sdk npm install weixin-js-sdk二、引入 var jweixin require(jweixin-module);三、使用 调用接口 一般调用成功会返回debug&#xff0c;appId&#xff0c;timestamp&#xff0c;nonceStr&#xff0c;signature等参数注…

RK3588平台开发系列讲解(AI 篇)RKNN-Toolkit2 API 介绍

文章目录 一、RKNN 初始化及对象释放二、RKNN 模型配置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解 RKNN-Toolkit2 API 详细说明。 一、RKNN 初始化及对象释放 在使用 RKNN Toolkit2 的所有 API 接口时,都需要先调用 RKNN()方法初始化 RKNN 对象,…

HAProxy 调度算法介绍

HAProxy 调度算法介绍 HAProxy 的调度算法比较多&#xff0c;在没有设置 mode 或者其它选项时&#xff0c;HAProxy 默认对 后端服务器使用 roundrobin 算法来分配请求处理。对后端服务器指明使用的算法 时使用balance关键字&#xff0c;该关键字可在listen和backend中出现。在…

使用Nodejs搭建简单的HTTP服务器 - 内网穿透公网远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址&#x1f340;小结&#x1f340; &#x1f389;博客主页&#xff1a;小智_x0___0x_ &#x1f389;欢迎关注&#xff1a;&…

“车-路-网”电动汽车充电负荷时空分布预测(matlab)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考《基于动态交通信息的电动汽车充电负荷时空分布预测》和《基于动态交通信息的电动汽车充电需求预测模型及其对配网的影响分析》文献模型&#xff0c;考虑私家车、出租车和共用车三类交通工具特性和…

Python支持下最新Noah-MP陆面模式站点、区域模拟及可视化分析技术

查看原文>>> Python支持下最新Noah-MP陆面模式站点、区域模拟及可视化分析技术 熟悉陆表过程的主要研究内容以及陆面模型在生态水文研究中的地位和作用&#xff1b;深入理解Noah-MP 5.0模型的原理&#xff0c;掌握Noah-MP模型&#xff08;2023年最新发布的5.0版本&am…

Android 查看签名文件的MD5 SHA1值

1.找到存放签名文件所在的文件夹 2.输入命令&#xff1a;keytool -list -v -keystore atui.jks 3.输入口令&#xff08;keystore.jks签名文件的密码&#xff09;

牛客网 读取写入数据

牛客网写题与leetcode不同&#xff0c;并没有给输入的数据&#xff0c;而是需要自己从控制台地区并格式化 import sys if __name__ "__main__":# 读取一个数n int(sys.stdin.readline().strip())# 读取一个整型的列表&#xff0c;输入时是以字符串的形式输入的&am…

Linux管理SpringBoot应用shell脚本实现

Liunx系统如何部署和管理SpringBoot项目应用呢&#xff1f;最简单的方法就是写个shell脚本。 Spring Boot是Java的一个流行框架&#xff0c;用于开发企业级应用程序。下面我们将学习如何在Linux服务器上部署Spring Boot应用&#xff0c;并通过一个脚本实现启动、停止、重启等操…