计算机基础:源码反码补码 位运算。盘点源码常见的位运算操作,祝您源码阅读更上一层楼。

Posted pumpkin的玄学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机基础:源码反码补码 位运算。盘点源码常见的位运算操作,祝您源码阅读更上一层楼。相关的知识,希望对你有一定的参考价值。

源码、反码、补码

计算机中对数字的编码表示有三种方式:「原码」「反码」「补码」

「原码」:原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1。比如十进制10如果用8个二进制位来表示就是 00001010, -10就是 10001010

「反码」:反码表示方法:正数的反码是其本身;负数的反码是在其原码的基础上,符号位不变,其余各个位取反

「补码」:补码表示方法:正数的补码是其本身;负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。(即在反码的基础上+1)

这三种是编码方式,但是在计算机系统中,数值一律用补码来表示(存储)。

举个🌰

1. 10
  原码           反码         补码
00001010  --> 00001010 --> 00001010
2. -10
10001010  --> 11110101 --> 11111011  

位运算

简介

各种编程语言都提供了对补码的二进制位直接进行运算的方法,「位运算」

符号描述规则
&相同位的两个数字都为1,则为1;若有一个不为1,则为0。
|相同位只要一个为1即为1。
~0和1全部取反。
^亦或相同位不同则为1,相同则为0。
<<左移a << b就表示把a转为二进制后左移b位(在后面添b个0)。
>>右移a >> b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。 带符号右移。正数右移高位补0,负数右移高位补1。
>>>无符号右移无符号右移。无论是正数还是负数,高位通通补0

举几个🌰

10 & -15 = 00001010 & 11110001

00001010
11110001 &
   ||
00000000

按位进行相与,相同为1则为1,否则为0,最终算的结果为000000000
10 & 15 = 00001010 & 00001111

00001010
00001111 &
   ||
00001010

按位进行相与,相同为1则为1,否则为0,最终算的结果为0000101010
10 | 15 = 00001010 | 00001111

00001010
00001111 |
	||
00001111

按位进行相与,相同为1则为1,否则为0,最终算的结果为0000101010
15>>2

00001111 -00000011

二进制右移2位,左边填符号号位,右边抹掉,得到000000113

相当于15/2^2 向下取整
15<<2

00001111 -0000111100

二进制左移2位,左边抹掉,符号位不变,右边填0,得到00111100等于60

相当于15*2^2

记录源码中常见到的位运算

源码要这样做?

位运算可以提升程序性能,有时还可以简化逻辑。当然也有不易阅读的弊端。但瑕不掩瑜,运用好位运算,对程序性能的提升有很大的帮助。

下面盘点一下常见的位运算操作,祝您阅读源码更上一层楼!

求模运算

一般都会见到求模运算:

int mod = num & (length-1)

什么意思呢?如下所示

a % b == a & (b - 1)

那么可以完全取代%的位运算吗?

不可以,位运算只能在b 为 2^n时使用

原理解析

X % 2^n = X & (2^n - 1)
设 n 为 4,则 2^4 = 16,表示成 2 进制就是 00010000。2^4 - 1 = 15 ,即 00001111。
X & (2^4 - 1) 就相当于取 X 的 2 进制的后四位数。
而X / 2^4 相当于 X >> 4,即把 X 右移 4 位,此时得到了 X / 2^4 的商,而被移掉的部分(后>四位),则是 X % 2^4 的结果,也就是余数。

推广一下
对于所有的2^n的数,
二进制表示位:000…10000…000
则,而 2^n - 1 的二进制为:000…01111…111
X / 2^n 是 X >> n,所以 X & (2^n - 1) 就是取被移掉的后 n 位,也就是 X % 2^n。

左移右移运算符

比如ArrayList里面的初始化容量的源码使用到了>>

int newCapacity = oldCapacity + (oldCapacity >> 1);

什么意思呢?等于老的容量+老的容量/2^1

比如 找出不大于N的最大的2的幂指数,使用<<代替了*

    var sum = 1
    while (true) {
        if (sum << 1 > 9) {
            log(sum)
            break
        }
        sum = sum << 1
    }

但是还可以这么写👀

 	n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n + 1) >>> 1;

//解析  比如输入的n=9
               0000 1001
 无符号右移一位 0000 0100
 或运算        0000 1100
 无符号右移两位 0000 0011
 或运算        0000 1111
 
 以后的操作均是0000 1111,最后加1 在右移 等于 0000 1000   == 8

加餐:Kotlin位运算表示法

kotlin描述java
and(bits)位与&
or(bits)位或\\
inv(bits)位非~
xor(bits)位异或^
shl(bits)左移<<
shr(bits)右移>>
ushr(bits)无符号右移>>>

Kotlin中的 位运算符 只对Int和Long两种 数据类型 起作用!

你学废了吗?🤷‍♂️

以上是关于计算机基础:源码反码补码 位运算。盘点源码常见的位运算操作,祝您源码阅读更上一层楼。的主要内容,如果未能解决你的问题,请参考以下文章

位运算学习笔记

计算机补码原码问题

数电:原码反码补码以及运算中的位宽问题

知道 补码,如何 计算 原码

位运算符以及源码补码反码

逻辑运算和位运算