• 算法通关村第十一关青铜挑战——移位运算详解


    大家好,我是怒码少年小码。

    计算机到底是怎么处理数字的?

    数字在计算机中的表示

    机器数

    一个数在计算机中的二进制表示形式,叫做这个数的机器数。

    机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1。比如,十进制中的数+3,计算机字长为8位,转换成二进制就是00000011。如果是-3,就是10000011。这里的 00000011 和 10000011 都是机器数。

    真值

    将带符号位的机器数对应的真正数值称为机器数的真值。

    例如上述-3的机器码10000011的真值是-3而不是131。(10000011换成十进制是131)


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

    原码

    第一位表示符号,其余位表示值。例如如果是八位二进制:

    • [+1] 原 = 0000 0001
    • [-1 ] 原 = 1000 0001

    八位二进制有一位用于表示符号,所以原码的表示范围是[-127,127]。

    反码

    • 正数的反码是其本身
    • 的反码是在其原码的基础上,符号位不变,其余各位取反。
    • [+1] = [00000001]原 = [00000001]反
    • [-1] = [10000001]原 = [11111110]反

    补码

    • 正数的补码就是其本身
    • 负数的补码是在其原码的基础上你,符号位不变,其余各位取反,最后+1(也就是在反码的基础上+1)
    • [+1] = [00000001]原 = [00000001]反 = [00000001]补
    • [-1] = [10000001]原 = [11111110]反 = [11111111]补

    看到这里你应该知道一个数在计算机中有三种编码方式。

    拓展:反码、补码在人脑无法直观的看出来它的数值,那为啥还要有它们?

    答:人脑可以知道第一位是符号位,在计算的时候我们会根据符号位选择对真值区域的加减。但是计算机要辨别"符号位"就必须获得全部的位的数据才可以,显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法。例如:根据运算法则减去一个正数等于加上一个负数。

    1+(-1)=[00000001]反 + [11111110]反 = [11111111]反=[10000000]原 = -0

    "0"的表示有点奇怪,+0和-0是一样的,而且0带符号是没有任何意义,而且要浪费[0000 0000]原和[10000000]原两个编码来表示0。于是补码的出现,解决了0的符号以及两个编码的问题:

    1 + (-1) =[0000 0001]原 + [10000001]原= [00000001]补 + [1111 1111]补= [0000 0000]补=[0000 0000]原

    [10000000]表示-128,所以补码的范围是[-128, 127]。(八进制中)

    位运算规则

    位运算主要有:与、或、异或、取反、左移和右移,其中左移和右移统称位移位运算,移位运算又分为算术移位和逻辑移位。

    与运算的符号是&

    运算规则:对于每个二进制位,当两个数对应的位都为1时,结果才为1,否则结果为0。

    0 & 0 = 0
    0 & 1 = 0
    1 & 0 = 0
    1 & 1 = 1
    
    • 1
    • 2
    • 3
    • 4

    或运算的符号是|

    运算规则:对于每个二进制位,当两个数对应的位都为0时,结果才为0,否则结果为1

    0 | 0 = 0
    0 | 1 = 1
    1 | 0 = 1
    1 | 1 = 1
    
    • 1
    • 2
    • 3
    • 4

    异或

    异或运算的符号是⊕(代码表示是^)

    运算规则:当两个数对应的位相同时,结果为0,否则结果为1

    00 = 0
    01 = 1
    10 = 1
    11 = 0 
    
    • 1
    • 2
    • 3
    • 4

    取反

    取反运算的符号是~

    运算规则:对一个数的每个二进制位进行取反操作,0变成1,1变成0

    ~0 = 1
    ~1 = 0
    
    • 1
    • 2

    移位运算

    移位运算按照移位方法分类可以分成左移和右移,按照是否带符号分类可以分成算术移位和逻辑移位

    • 原始: 0000 0110 ===> 6
    • 右移一次: 0000 0011 ===> 3 相当于除以2
    • 左移一次: 0000 1100 ===> 12 相当于乘以2

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

    • 算术右移时,高位补最高位;
    • 逻辑右移时,高位补0
    • 示例1:29的二进制表示是0001 1101。 29左移2位的结果是116,对应的二进制是01110100;29左移3位的结果是-24,对应的二进制是11101000
    • 示例2:-50的二进制表示是11001110(补码)。-50算术右移2位的结果是-13,对应的二进制表示是11110011;-50逻辑右移2位的结果是51,对应的二进制表示是00110011

    拓展:计算机内部的右移运算采取的是哪一种?

    答:

    • 对于 C/C++ 而言,对于有符号类型,右移运算为算术右移;对于无符 号类型,右移运算为逻辑右移。
    • 对于 Java 而言,不存在无符号类型,所有的表示整数的类型都是有符号类型,因此需要区分算术右移和逻辑右移。在Java中,算术右移的符号是>>,逻辑右移的符号是 >>>。

    位运算常用技巧

    位运算代码套路

    获取

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

    boolean getBit(int num,int i){
    	return ((num&(1<<i))!=0);
    }
    
    • 1
    • 2
    • 3

    设置

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

    int setBit(int num,int i){
    	return num | (1 << i);
    }
    
    • 1
    • 2
    • 3

    清零

    与setBit相反,将1左移i位获得形如00010000的值,对这个值取反进而得到类似11101111的 值,接着对该值和num执行”位与“,故而不会影响到num的其余位,只会清零i位。

    int clearBit(int num,int i){
      int mask = ~(1 << i);
      return num &mask;
    }
    
    • 1
    • 2
    • 3
    • 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);
    }
    
    • 1
    • 2
    • 3
    • 4

    END

    说实话,更文到这里其实有点累了,学计算机也有点累了。网上负面消息一大堆,近几年就业形势不好,自己在学的东西也得不到正向反馈,有时候真的觉得自己挺废物的😔。或许看到这的小伙伴也和我有一样的想法,这里我想分享一段翁凯老师的话:

    计算机的所有东西都是人做出来的,别人能想得出来的,你也一定能想得出来。在计算机里头没有任何黑魔法,所有的东西只不过是我现在不知道而已,总有一天我会把所有的细节、所有的内部的东西都搞明白了。

    这贼船都上了,咱就好好走下去吧😁

  • 相关阅读:
    ​iOS安全加固方法及实现
    JdbcTemplate学习札记
    LeetCode每日一题——1206. 设计跳表
    jquery.i18n.properties.js使用及seo优化
    传染病学模型 | Matlab实现SEIR传染病学模型 (SEIR Epidemic Model)
    UEC++ day7
    深入浅出PyTorc——进阶训练技巧
    达梦在备份数据库时报错归档日志不连续
    暗黑破坏神资unity资源分包精讲
    PHP+防止SQL注入的网上二手交易平台 毕业设计-附源码241552
  • 原文地址:https://blog.csdn.net/m0_74469506/article/details/133998182