首页 > 其他分享 >【位运算】二进制中1的个数 (lowbit运算)

【位运算】二进制中1的个数 (lowbit运算)

时间:2023-12-25 18:11:06浏览次数:28  
标签:10 反码 运算 二进制 lowbit 补码 原码 0001

lowbit的概念

我们知道,任何一个正整数都可以被表示成一个二进制数。如:

(2)10=(10)2

(4)10=(100)2

那么定义一个函数f(x) = lowbit(x),输入一个十进制数,返回二进制中最低一位的1所表示的值,如lowbit(4)=4

 

先了解原码 补码 反码

原码:是最简单的机器数表示法。用最高位表示符号位,‘1’表示负号,‘0’表示正号。其他位存放该数的二进制的绝对值
举例

    1010 : 最高位为‘1’,表示这是一个负数,其他三位为‘010’,
    即(0*2^2)+(1*2^1)+(0*2^0)=2(‘^’表示幂运算符)
    所以1010表示十进制数(-2)
    同理 0010表示十进制数(2)

    0001+0010=0011 (1+2=3)ok

    0000+1000=1000 (+0+(-0)=-0) ok

    0001+1001=1010 (1+(-1)=-2)no

    由此引出了反码的概念来解决1 + -1 = -2的问题
反码:正数的反码还是等于原码,负数的反码就是他的原码除符号位外,按位取反。
举例

    若以带符号位的四位二进制数为例:
    3是正数,反码与原码相同,则可以表示为0011
    -3的原码是1011,符号位保持不变,低三位(011)按位取反得(100)所以-3的反码为1100

    0001(1 )+1110 (- 1)=1111(-7)no  正确答案为0

    1110(-1)+1101(-2)=1011(-4)no   正确答案为-3

    1110(-1)+1100(-3)=1010(-5)no   正确答案为-4

    细心的你可能发现,除了第一个,其他计算错误的结果差值只是相差了1

    由此引出了补码的概念来解决问题
补码:正数的补码等于他的原码, 负数的补码等于反码+1。也等于正数反码+1。

    可能有小伙伴疑惑为什么  0001(1 )+1110 (- 1)=1111(-7)no  正确答案为0
    如果这个+1不是会错误吗??
    哈哈,显然不是 
    机器码的位数在操作系统中是固定位,假设只有4位
    源码 1 : 0001   -1:1001
    补码 1 :0001   -1:1110 + 1 = 1111
    补码相加 1 + -1 = 0001 + 1111 = 10000,因为保留4位,所以最终结果为0000
    nice~~完美

    负数的补码等于反码+1,也等于正数反码+1。
    1.  -1 :1001  -> 1111
    2.  -1 : (1: 0001)的反码 1110 + 1 -> 1111

 

lowbit函数有两种实现方法:

1.

x&(x^(x-1))

2.

x&-x

 

我们先来解释第一个,还是先拿(6)10举例

(6)10-(1)10=(5)10

(110)2-1=(101)2

 

我们发现,根据小学数学减法运算的借位原则(滑稽),对一个二进制数进行减1,那么会出现从这个这个数的最后一个1开始到最后的所有数都取反,即构成一个01111⋯的串

我们把这个数与原数异或,就会造成:第一个1以后的数(包括第一个1)全部取1.其他的位全部取0.即构成一个由一堆0后面跟一堆1的串。

那么再把原式做一个与运算,那么除了原来的那个1(对应位都是1)为1,其他位全是0,完成任务。

 

现在来解释第二个,依旧拿(6)10举例子

根据计算机的补码的性质,补码等于原码的反码+1

-x = ~x + 1

例子:

x = (9)10 = 0 1001

-x = 1 0110 + 1 = 1 0111

再做与操作,得0 0001,这样就得到第一个1

 

用lowbit运算统计1的个数

我们可以使用lowbit运算统计一个整数的二进制形式下1的个数。

实现原理很简单啦,就是:我们先用lowbit运算找出lowbit(x),然后用原数减去这个数,依次循环,直到为0为止。

这也是树状数组的实现原理。

#include <iostream>

using namespace std;

int lowbit(int x){
    return x & -x;
    //-x = ~x + 1 //(x取反加1)
}

int main(){
    int n;
    cin >> n;

    while(n --){
        int x;
        cin >> x;
        int res = 0;
        while(x) {
            x -= lowbit(x);
            res ++;
        }
        cout << res << " ";
    }
    return 0;
}

lowbit运算的应用

关于lowbit运算,最著名的应用应该算是树状数组。但是lowbit的神妙远远不止树状数组,在很多二进制和位运算的相关题目中,都有lowbit运算的影子。甚至,在状态压缩DP中,lowbit也扮演着一份不可忽视的角色。

标签:10,反码,运算,二进制,lowbit,补码,原码,0001
From: https://www.cnblogs.com/Yukie/p/17926707.html

相关文章

  • MSSQL执行查询报错“使用 UNION、INTERSECT 或 EXCEPT 运算符合并的所有查询必须在其
     MSSQL执行查询报错“使用 UNION、INTERSECT 或 EXCEPT 运算符合并的所有查询必须在其目标列表中有相同数目的表达式。”报错截图: 根本原因如提示,列不一致,列的个数和列名,顺序都需要一致。 ......
  • 第81讲:清理MySQL Binlog二进制日志的方式
    1.清理Binlog二进制日志的依据Binlog日志非常重要,但是占用的磁盘空间也很大,我们也需要定期的去清理二进制日志,在MySQL数据库中,提供了自动清理Binlog日志的参数,根据指定的天数,保留n天内的Binlog日志,也可以手动人为删除。在手动删除Binlog日志时,要切记不要使用rm-rf直接删除Binlog......
  • Day05位运算符
    位运算符//位运算符:&,|,^,<<,>>//位运算,与二进制有关A=00111100B=00001101A&B=00001100//按位与(&),对于两个操作数的每一个对应位,如果两个位都是1,则结果位为1,否则为0A|B=00111101//按位或(|),对于两个操作数的每一个对......
  • Day05逻辑运算符
    逻辑运算符//与(and)或(or)非(!,取反)booleana=true;booleanb=false;System.out.println("a&&b:"+(b&&a));//与运算:两个変量都为真,结果才为trueSystem.out.println("a||b:"+(a||b));//算:两个量有一个真,结果为trueSystem.out.println("!(a......
  • 无涯教程-PostgreSQL - 运算符
    运算符是保留字或字符,主要用于PostgreSQL语句的WHERE子句中以执行操作,如比较和算术运算。运算符用于指定PostgreSQL语句中的条件,并用作语句中多个条件的结合。算术运算符比较运算符逻辑运算符按位运算符PostgreSQL算术运算符假设变量a=2,变量b=3,则-运算符描述示例......
  • 输入 10 进制数转换为二进制进行输出
    #define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>intmain(){ intj=0;//用于记录每个二进制位(倒叙) ints=0;//记录输入的数 intarr[256]={0}; printf("请输入数字\n"); scanf("%d",&s); inttmp=s; inti=1;//731 while(s>......
  • 2023南海区信息学区赛(初中组) T1二进制整除
    第1题   二进制整除 查看测评数据信息交换二进制数相邻两个位置的数字,需要花费1元的代价。读入整数n以及n位二进制数(也许有前导0),你需要依次回答n个独立的问题,第i个问题(1<=i<=n)是这样的:假如要使得读入的二进制数是2^i的倍数,至少需要花费多少元的代价?如果不可能,则输出......
  • 谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64
    JavaScript提供了一些API来处理文件或原始文件数据,例如:File、Blob、FileReader、ArrayBuffer、base64等。下面就来看看它们都是如何使用的,它们之间又有何区别和联系!1.BlobBlob全称为binarylargeobject,即二进制大对象,它是JavaScript中的一个对象,表示原始的类似文件......
  • 运算符--原码、反码、补码
    运算符--原码、反码、补码原码:十进制数据的二进制表现形式,最左边是符号位,0为正,1为负。利用原码对正数进行计算是不会有问题的。但如果是负数计算,结果就出错,实际运算的结果,跟我们预期的结果是相反的。原码的弊端:利用原码进行计算的时候,如果是正数完全没有问题。但是如果是......
  • day 03-3 Python基础-运算符
    3.运算符3.1常见的运算符算数运算符运算符描述示例+加-减*乘/除%取模-返回除法的余数10%3结果输出1**指数-幂,x的y次幂2**3结果输出位8//整除-返回商的整数部分9//2结果输出为49.0//2.0结果输出位4.0比较运算符运算符......