ja 移位运算

Ja位操作我们必须知道的(不限于Ja)-陈碧婷黄金-博客花园

基本概念

1.目前常见的CPU位有32位和64位。所谓32位处理器,一次只能处理32位,也就是4个字节的数据,而64位处理器一次可以处理64位,也就是8个字节的数据。

2、一个字节(1Byte)等于8 8bits (8位),是计算机存储数据的最小单位,即存储的数据是一系列二进制位信息。每一位用0或1来表示。(注意大B和小B的区别)

3.为什么一个字节是8位?
现在普遍的说法是8位可以覆盖所有的字符编码,即ASCII编码。但历史上也曾出现过4位或7位为1字节,但在随后的字符集标准统一中逐渐被8位取代的场景。除了历史原因,还有数据存储的需要(必须能够用一个字节表示100个以上的状态,包括常用的数字、大小写字母等。),而且早期的计算机存储昂贵,所以8bit也是当时顺应二进制特性的必然结果。

4、二进制加减,加法:0+0=0,0+1=1,1+0=1,1+1=10,每2进1。

5、二进制到十进制和十进制到二进制。

上面列出了一些基本概念和相应的参考链接,建议先了解一下。特别是二进制和十进制的转换以及二进制的加减规则,后面会详细涉及。

机器数、真值

人类使用十进制只是因为我们有10个手指。如果有一天你看到一个只有四根手指的外星人,那么他一定会用四元,如图:

java 移位运算

如果你能看懂上图,你就已经明白了十进制和手指的关系。现代计算机中使用门电路,它们只能代表两种状态:0或1。如果计算机是人,那么它只有两个手指,所以用二进制。
是的,没错。所谓十进制,其实并不是什么神秘的东西,只是数字的一种表示。门概念

机器数

机器号有两种:无符号号和有符号号。

一个数在计算机中的二进制表示称为这个数的机号。机器的数量是有符号的。在计算机中,符号以一个数的最高位存储,正数为0,负数为1。

比如十进制数+3,计算机字长是8位,换算成二进制就是00000011。

如果是-3,就是10000011。所以,00000011和10000011这里是机器的数量。

真值

因为第一位是符号位,所以机器号的形式值不等于真实数值。

例如,上面的有符号数10000011,其最高位1表示负,其实数值为-3,而不是形式值131(10000011转换为十进制,相当于131)。

因此,为了区别起见,将签名的机号对应的真数值称为机号的真值。

例如:真值0000 0001 =+000001 =+1,真值1000 0001 =-000001 =-1。

原码、反码、补码

为了妥善处理数据运算中的符号位问题,出现了将符号位和数值位编码在一起表示相应数字的各种表示方法。比如我们熟悉的原码、反码、补码、移码等等。通常,未编码的数字称为真值,编码的数字称为机器码或机器码。

计算机目前使用的机器数量是补数的方式。在探讨机器为什么要用补码之前,我们先来了解一下原码、补码、补码的概念。对于一个数字,计算机要用一定的编码方法来存储。原码、补码、补码是机器存储特定数字的编码方法。

原码

原始代码是符号位的绝对值加上真值,即第一位代表符号,其余位代表值。例如,如果是8位二进制:

[+1]Original = 0000001[-1]Original = 1000 0001第一位是符号位。因为第一位是符号位,所以8位二进制数的取值范围是:

[011111111,1111111]转换为真值后,即:

[127,-127]原码是人脑最容易理解和计算的表示。原码也可以理解为最原始的机器码。

反码

反码的表示是:
正数的反码是它本身,
负数的反码是以它的原码为基础,符号位不变,其他位反转。

[+1]=[00000001]Original =[0000001]Anti[-1]=[10000001]Original =[11111110]Anti-visible如果一个anti-code代表一个负数,人脑无法直观地看到它的值。通常要转换成原码再计算。

补码

补码的表示是:
正数的补码是它本身,
负数的补码是以它的原码为基础,符号位不变,其他位反转,最后+1。(即在逆码的基础上+1)。

[+1]=[00000001]Original =[0000001]Inverse =[0000001]Complement[-1]=[10000001]Original =[11111110]Inverse =[1111111]Complement对于负数,补数的表示。

互相转换、注意事项

注:我们在最初的基本概念中提到了二进制和十进制的转换方法。但需要知道的是,一个数在计算机中的二进制表示叫做机数。

而机数是有符号的,所以我们会把符号存储在对应的最高位,0个正位,1个负位。所以机器的数量不等于二进制。

这就引出了真值的概念,比如符号数10000011,在十进制中对应的值是131,但在机数中,因为1代表负数,所以它的真值是-3,而不是131。

符号编号:10000011。我们需要先消除其符号位的影响,将其调整为正数:0000011。这时我们将正数转换成十进制到3,再加上起始符号位表示一个负数,所以是-3。

要知道二进制只是一种以2为基数的计数方法,在二进制中是无法区分正数和负数的。但是,如果要区分正数和负数,必须在二进制的最高有效位使用0和1来表示符号。那么此时最有意义的0和1就不是二进制计数方法,而只是一个符号标识,符号标识永远不能直接参与二进制计算。

当我们用最高有效位的0和1来表示正负时,二进制数就不再是符合二进制规则的数,而是一个机器数。

二进制只是一种以2为基数的计算方法。此时最高位的值不再用2位基数的计算方法计算,而只是一个表示正负的符号,所以此时的值不再是一个符合二进制规则的数,而是一个机器数。

所以,只有机器的数量才能代表正反。机器数量对应的结果是真数,不是小数。

如果这时候抛出一个问题:10000011换算成对应的十进制,那么对应的结果就是131,但如果换算成实数,就是-3。同样,00000011如果转换成对应的十进制,就是3,如果转换成实数,也是3。

所以当我们看到一个用8位数表示的二进制数时,一定要确认这个二进制数代表的是机号还是二进制数。是转换成十进制数还是实数。最大的区别是最高符号位是参与二进制运算还是只代表符号位。

机号转实数:
10000011 >先消除最高位1的影响,将其变为正数> 00000011 & gt然后正数被转换成二进制形式的十进制数>:3 & gt此时,将原符号加回> 3调整为-3。

二进制数转十进制数:
10000011 >不消除最高位1 >的影响直接转换为正数;10000011 & gt然后正数被转换成二进制形式的十进制数>:131 & gt无需添加符号位>;131还是131。

所以可以看出,实数和小数最大的区别就是是否忽略最高有效位。确认是否忽略最高有效位,得到初始正数后,正数的计算方法和二进制转十进制完全一样。其实就是二进制到十进制。哈哈。

然后在注意了二进制数和机号以及十进制数和实数的区别之后。我们需要注意的另一个问题是:

机数包括原码、补码和补码。其中三种可以相互转换。原码转换成补码,上面已经解释过了,补码也可以逆向思维转换成原码。

这里需要知道的是,补码和补码当然不能直接转换成实数,只能通过原码进行转换。

其实这并没有错。毕竟原码经过层层转换得到它的补码,补码可以直接转换成实数。当然是不可能的。

那么,原码为什么需要转换成补码,原码为什么不是计算机计算方法,而是补码呢?

本文的原文地址是https://www.cnblogs.com/zh94/p/16195373.html.

原创声明:作者:陈,博客地址:

为什么补码才是计算机的真正计算方式

现在我们知道计算机可以有三种编码方法来表示一个数。对于正数,三种编码方法的结果是相同的:

[+1]=[00000001]Original =[0000001]Anti =[000000001]Complement所以不需要过多解释。但是对于负数:

[-1]=[10000001]Original =[1111110]Inverse =[1111111]补码原码,补码和补码是完全不同的。既然原码被人脑直接识别并用来计算表示,为什么还有补码和补码?

首先,因为人脑可以知道第一位是符号位,所以我们在计算时会根据符号位选择加减真值区域。
但是对于计算机来说,加减乘法器已经是最基本的运算了,设计要尽量简单。符号位& # 34;显然会让电脑的基本电路设计变得非常复杂!所以人们想出了一个方法,在运算中涉及符号位。我们知道减去一个正数等于加上一个负数,根据运算定律,即1-1 = 1+(-1) = 0,所以机器只能加不能减,这就使得计算机运算的设计更加简单。

于是人们开始探索在运算中加入符号位的方法。先看原码:
计算十进制表达式:1-1=0。

1-1 = 1+(-1)=[0000001]Original+[1000001]Original =[10000010]Original =-2如果用原码表示一个数,而且计算中还涉及符号位,显然对于减法来说结果是不正确的。这就是为什么原始代码在计算机中不用来表示一个数字。
为了解决原码的减法问题,有一个反码:
小数计算的表达式:1-1=0。

1-1 = 1+(-1)=[0000001]original+[1000001]original =[0000001]anti+[1111110]anti =[1111111]anti =[1000000]original =-0 & # 34;在这个特殊的数值中,虽然人们理解+0和-0是一样的,但是0的符号是没有意义的,会有[0000 0000]和[100000000]两个代码来表示0。

所以补码的出现解决了0符号和两种编码的问题:

1-1 = 1+(-1) = [0000 0001]原文+[1000 0001]原文= [0000 0001]增补+[1111 111]增补= [0000 0000]原文在此说明。

这样0用[0000 0000]表示,而之前有问题的-0不存在,可以用[1000 0000] -128表示:

(-1)+(-127)=[1000 0001]Original+[11111111]Original =[1111 1111]Complement+[1000 0001]Complement =[1000 0000]由于我们用原码表示时序,所以最大值为:01111。
这里用了补码后,补码的规则是:第一位不变,其他倒位,+1。所以(-1)+(-127)正好是-128。

使用补码不仅可以解决0的符号和两个代码的问题,而且可以表示一个最低数。这就是为什么8位二进制在使用原码或补码时取值范围是[-127,+127],而在使用补码时取值范围是[-128,127]的原因。

因为机器用的是补码,所以编程常用的32位int的取值范围可以是:[-2的31次方,2的31次方-1]因为第一位代表的是符号位,而用补码的时候可以保存一个最小值。

很神奇,当我们第一次用原码做加法的时候,因为我们的大脑还需要判断最高位的符号,才能进行二进制运算,然后加上相应的符号位。使用补码后,对应的符号位直接参与运算,补码的值直接相加,结果正好是二进制转换后的结果。这样,计算机的基本电路设计可以更简单,不用注意符号位问题,只按二进制加法法则。太完美了所以这也是补码是计算机真正计算方法的原因之一!

但是,补码后得到的值只是直接二进制值相加的结果。真的只是这么巧合吗?其实不是,但也包含了这个有趣的数学原理。详见:
深刻理解原码补码数的机器码表示法&机器码原理&原码补码原理。

位运算

在文章的顶部,列举了基本概念为“十进制二进制转换”和对应“二进制加减”的相关链接。
这里推荐几个在线计算的网站,方便我计算结果的二次验证:
在线原码、补码、十进制转换&在线二进制转换&在线二进制加减法。

然后开始涉及到位操作。

概念

什么是比特运算?我们先来看看百度百科的概念:

程序中的所有数字都以二进制形式存储在计算机内存中。位运算是直接对内存中整数的二进制位进行运算。百度百科给出的解释模棱两可。按照百度百科的解释,如果直接对内存中整数的二进制位进行运算就是位运算,那么用二进制数进行算术运算(+、-、*、/)不也是位运算吗?

我们来看看维基百科给出的概念解释:

位操作是程序设计中位模式或二进制数的一元和二元运算。在很多古代的微处理器上,位运算比加减运算略快,通常位运算比乘除运算快得多。在现代架构中,情况并非如此:位运算通常与加法运算相同(仍然比乘法运算快)。维基百科中比特运算的概念相对合理。通过维基百科中的概念,我们可以清楚的分辨出位运算不同于加减乘除。不同CPU对位运算的操作比(乘/除)运算快。

所以这才是我们需要知道比特运算的真正原因,就是CPU处理器对于比特运算符的计算比算术运算符要快!在特定的编码场景下,位运算的执行速率远高于算术运算!

网络上对于位运算有很多解释:位运算是直接对内存中整数的二进制位进行运算,所以位运算更节省内存,提高运算效率。其实这是一个很不严谨的说法,很容易误导人们对位运算的理解,因为所有的整数在计算机里最终都是二进制数,所以对整数的所有运算都不是位运算?当然不是。而且位运算之所以真的快不是因为节省内存,主要是因为CPU对位运算的支持!而且和记忆关系不大。为什么位操作CPU更快?程序中的基本操作包括:

算术运算:加、减、乘、除、取余按位运算:按位或“|”、按位与“&”、按位取反“~”、按位异或“^”移位运算:左移x<<k;右移x>>k

其中,位运算和移位运算属于位运算的范畴。

下面将详细解释位操作的具体执行逻辑。这里用按位运算中的AND运算符“&”来简单解释一下按位运算的主要执行逻辑:
AND运算符的运算规则是:当两位都为1时,结果为1。例如,3&5表示00000011 & 0000101 = 00000001,因此3&5的值为1。

按照AND运算符的规则,位运算的整体执行逻辑其实比较简单,更多的是比较位数,从而得出一个结果。对于CPU处理器来说,这种相对简单的运算逻辑在电路设计上会简单很多。以下是与运算符所涉及的CPU电路图:

对于一个分部,CPU中相应的电路图设计如下:

可以看出,整个CPU电路图的设计复杂了不止一级,所以这也是位运算比我们常用的算术运算快的直接原因。因为整个CPU的执行逻辑从设计层面来说要复杂得多。

当然,说到CPU的电路图设计,就不得不提到相应CPU中晶体管的特性,晶体管所涉及的开关(01)的特性也构成了逻辑电路,从而形成与门、或门、非门、异或门等电路特性。
此内容请参考以下链接:
位操作中隐藏的CPU秘密
程序中的位操作在基本电路
基本电路中的位操作原理——知乎
四位计算机及实现
位操作
程序的理解。

CPU中的电路设计和数学算法的实现有着微妙的联系,计算机前辈的力量是无穷的。至此,我们知道程序中基本操作执行率的真正差异其实是在CPU的层面。理解了这一点之后,我们就可以开始解释位操作符的真正执行逻辑了。
(位运算只需要比较01,以及移位等简单的逻辑运算,与直接执行二进制加法规则基本相同,在电路设计和逻辑上更简单,而乘除余数在电路设计上更复杂)

本文的原文地址是https://www.cnblogs.com/zh94/p/16195373.html.

原创声明:作者:陈,博客地址:

位运算符

你首先需要知道的是,在计算机中进行比特运算时,必须使用补码的方式来计算比特。因此,如果真值为负,必须先将其转换为补码,然后才能计算。

标志

形容

操作规则

&

当两位都为1时,结果为1。

|

或者

当两位都为0时,结果为0。

^

异或

这两位与0相同,但与1不同。

~

收回

0变成1,1变成0。

& lt& lt

左移

所有二进制位都左移几位,高位丢弃,低位用0填充。

& gt& gt

右移

所有的二进制数字都右移几位,对于无符号数字,高位用0补。不同的编译器有不同的处理方法,有的补码符号位(算术右移),有的补码0(逻辑右移)。

& operator的运算规则:只有两位数同时为1时结果为1,否则结果为0。

0&0=0 0&1=0 1&0=0 1&1=1示例:2&-2。

注:当然负数是以补数的方式计算的。

& 与运算符的用途:

根据AND运算符的计算特点,我们通常有以下几种用法:
1。判断奇偶性
我们知道,根据二进制和十进制(两个除外)的转换方法,如果是偶数,转换成二进制后最后一位必须是0,如果是奇数,最后一位就是1。例如:2 > 10,3 >11,100 >1100100,& gt1111001。

所以我们根据and运算符的运算规则,用if(a & 1)1作为奇数,if(a & 1)0作为偶数。
例如:
121 & 1 = 1111001 & 0000001 = 000001
2 & 1 = 10 & 01 = 00。

If (a% 2 == 0)完全可以用AND运算符代替,而bit运算符因为有CPU的支持,效率更高。

二进制转换成十进制的方式,参考基本概念中的URL即可。

2.取一个数的指定位
,比如取四个高位的数X=1010 1110,只需要另找一个数,使Y的四个高位为1,其余位为0,即Y=1111 0000,然后对X和Y进行and运算,(X & Y = 10101110 & 111100000。

如果想得到X的低四位数,只需将Y的低四位数设为1,其余位数设为0,(X & Y=1010 1110 & 0000 1111=0000 1110)就可以得到指定的X的低四位数..

| 或 运算符

运算规则:两位都为0时,结果为0。否则为1。

0|0=0 0|1=1 1|0=1 1|1=1示例:2 | -2 =-2。

| 或运算符的用途

首先,and和or是两个相反的概念,所以上面提到的and的目的在这里稍加修改也适用于or运算符。但是
目的是一样的,所以这里不重复对应相同目的的场景。

1.通常用于将数据的某些位设置为1
。比如把数X=1010 1110的低四位设为1,只需要再找一个数Y,使Y的低四位为1,其余位为0,即Y=0000 1111,然后对X和Y进行按位或运算(X|Y=1010 1111)。

类似地,使用&运算符,可以很容易地将一些位设置为0,比如上面提到的X&Y。如果X的低四位设置为0,那么
X & Y = 10101110 & 1110000 = 1010000。

以上说明灵活使用&和|其实也能达到同样的效果。然而,实际使用中并非如此。首先,对于上面低四位设置为1的场景,我们只需要找到一个数y,使得y的低四位为1,其余位为0。这样的数字很容易找到,并且是固定的数字,例如15。换算成二进制,就是1111。

但是如果用&运算符面对这个场景,就需要找到一个Y,Y的第四位是0,其余是1。这样的数字很难找,数值随着位数的不同而不断变化,比如:1111 0000=240,但如果是12位数,就是1111110000 = 4080。因此,在没有|操作符的情况下,使用&操作符会更方便。

虽然&和|的规则是相反的,可以灵活改变,但是对于具体的场景还是用具体的运算符比较好。

^ 异或运算符

运算规则:两位同为0,互不相同为1。

0 0 = 0 0 1 = 1 1 0 = 1 1 1 = 0示例:2-2

^ 异或运算符用途

1.交换两个号码

a=a^b;//a=a^bb=a^b;//b=(a^b)^b=a^0=aa=a^b;//A = (a b) (a b b) = 0 b = 0交换两个数的原理,也就是上面的笔记里写的东西。

要在没有位运算的情况下交换两个数,需要定义一个中间变量c来承担其中一个数的交换。对于Ja来说,定义一个新的int变量c意味着需要在内存中打开一个4字节空的空间。

因此,您可以根据服务特点选择合适的方法。如果对内存利用率有很强的要求,可以用位运算,没有要求,也可以。

静态void swap(int a,int b){ int c = a;a = b;b = c;}静态void swapBit(int a,int b){ a = a ^ b;b = a ^ b;a = a ^ b;} ~求反运算符的运算规则:0变1,1变0。

<< 左移运算符

运算规则:将一个操作数的所有二进制位左移若干位(左边的二进制位丢弃,右边用0填充)。

设a=15,即二进制数00001111,左移两位得到0011100,即十进制数60。

左移一位相当于数字乘以2,左移两位相当于数字乘以2 ^ 2 = 4。上述实施例15

设a=-46,补码是,1010 1110,a = a

设a=110,补数为:0110 1110,a = a

由此可见,左移n位等于乘以2的n次方。这个结论只适用于数字左移时溢出丢弃的高位不含1的情况。如果溢出的高位包含1,则不符合上述结论。

>> 右移运算符

运算规则:将一个数的二进制位全部右移若干位,正数在左边填0,负数在左边填1,右边丢弃。
例如:a = a & gt& gt2将a的二进制位右移2位,左补0或1取决于移位后的数是正数还是负数。

补码后设a=16,00010000,a = a

设a=-16,11110000补码后,a = a

结论:对于右移运算符,操作数每右移一次,就相当于把数除以2。

本文的原文地址是https://www.cnblogs.com/zh94/p/16195373.html.

原创声明:作者:陈,博客地址:

Ja位运算

位运算本身就是处理器和计算机本身提供的能力,所以位运算的使用实际上不限于任何编程语言。这里之所以以JA为例,主要是因为我常用的开发语言是JA,哈哈。

针对JA中位运算的使用,JDK其实有丰富的案例,比如:

1.在JDK ThreadPoolExecutor的实现中,使用了整数类型(4字节,32位),其中高3位保存线程池状态,低29位保存线程池中线程的有效数量。

2.例如,在JDK的HashMap中,初始化容量的数值通过位运算快速转换成2的n次方。并且在计算密钥的hash时,根据密钥的hash结果,通过位运算将hashCode的高16位和低16位混合,以降低hash碰撞的概率等等。

3.比如我们直接打开常用的Integer类的源代码,也会发现里面有大量的位运算。

这里只是通过上面的例子来说明位运算在Ja生态系统中的使用。其实是非常丰富的,而且由于位运算独特的计算特性,在一些相对特殊的代码场景中,使用位运算会出乎意料地简化问题。

如果你想了解更多JA中的使用场景和案例,我建议你直接看各种源代码就好了。

以上是一些例子,下面是一些小的补充说明:

ja中的bit运算只对int类型和Long类型有效(Ja中,Int的长度始终是32位,即4个字节,对整数的二进制数进行运算,而Long是64位,代表8个字节。),而对于byte、char、short,在使用这三种类型的时候,JVM会先转换成int类型再进行操作。

使用toBinaryString()将相应的小数转换为相应的补码。

system . out . println(integer . tobinary string(10));//1010 system . out . println(integer . tobinary string(-10));//11111111111111111111111111111111 system . out . println(long . tobinarystring(10));//1010 system . out . println(long . tobinary string(-10));//111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111有兴趣的话,看看Integer和Long对应的源代码就行了。

其它参考链接

以下参考链接仅供参考。部分链接中的内容可能会有一些歧义,请自行分辨。

祝读者看到的所有知识都能最终成为自己的知识!撒花!✿✿ヽ( ▽ )ノ✿!

位操作教程
位操作入门
ja位操作
位操作技巧
位操作的常用方式。

Ja位操作我们必须知道的(不限于Ja)-陈碧婷黄金-博客花园

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

发表回复

登录后才能评论