首页 > 编程知识 正文

原码反码补码转换例题(原码反码补码的关系)

时间:2023-05-06 18:43:51 阅读:98292 作者:1773

平时在阅读各种框架的源代码的过程中,经常会看到一些置换操作,所以作为一个Java开发人员,一定要掌握置换操作。

正数位移运算

Java中有三种置换操作:

:左移位:右移位:无符号右移位。我们直接来看看Demo:

system . out . println(21);//4

system . out . println(21);//1

system . out . println(21);//1

system . out . println(-2 ^ 1);//-4

system . out . println(-2 ^ 1);//-1

system . out . println(-2 ^ 1);//2147483647

乍一看,当您看到上面演示的打印输出时,您应该会感到困惑。接下来,让我解释一下这个结果是如何计算的。

上面的Demo中有“2”和“-2”,是两个十进制数,类型为int(Java中为四个字节)。位运算是以二进制位为基础的,所以我们在运算之前需要把十进制转换成二进制:

2.十进制“2”转换为二进制“00000000000000000000000000000000000”,然后二进制左移一位,高位丢弃,低位用0填充,结果为“00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000我们先看-2 1和-2 1。这两个负数的左移和右移操作其实和正数差不多。两者都是先把十进制数转换成二进制数,再移动二进制数,所以现在的关键是如何用二进制数表示负数。

原码、反码、补码

接下来我们主要介绍十进制数的二进制表示的不同方法,所以为了简洁,我们用一个字节,也就是八位来表示二进制数。

原码

十进制原始代码20000 0010-21000 0010

其实原码最容易理解,只是需要二进制的第一位数字来表示符号位,0表示正数,1表示负数。所以我们可以看到,如果一个数用原来的二进制码表示,取值范围是-111 1111 ~ 111,用十进制代替就是-127 ~ 127。

反码

在数学上,我们有加减乘除,但是对于计算机来说,最好只加,这样计算机会更简单,效率更高。我们知道在数学中,5-3=2实际上可以转化为5 (-3)=2,这意味着减法可以用加法来表示,而乘法是加法的累加,除法是减法的累加,所以在计算机中有加法就足够了。

很容易理解,一个数字由原始代码表示,但是需要一个单独的位来表示符号位。并且在添加时,计算机需要先识别一个二进制源代码是正的还是负的,然后进行相应的操作。这是没有效率的。电脑在操作时可以忽略符号位吗,也就是说让符号位也参与操作,这就需要用到反码了?

十进制原始代码补码20000 0010000 0010-21000 0010111 1101

正数的补码与原码相同,负数的补码是符号位在原码的基础上保持不变,其他位反相。

让我们看看如果用反码直接运算会发生什么。我们以5-3为例。

5-3等于5 (-3)

十进制代码补码50000 01010000 0101-31000 001111100

5-3

=5 (-3)

=0000 0101(反码)1111 1100(反码)

=0000 0001(反码)

=0000 0001(原始代码)

=1

这不对吗?5-3=1?为什么会有1的差别?

我们来看一个特殊的操作:

1-1

=1 (-1)

=0000 0001(反码)1111 1110(反码)

=1111 1111(反码)

=1000 0000(原始代码)

=-0

我们来看一个特殊的操作:

0 0

=0000 0000(反码)0000 0000(反码)

=0000 0000(反码)

=0000 0000(原始代码)

=0

我们可以看到,1000万意味着-0 00万。

00表示0,虽然-0和0是一样的,但是在用原码和反码表示时是不同的,我们可以理解为在用一个字节表示数字取值范围时,这些数字中多了一个-0,所以导致我们在用反码直接运算时符号位可以直接参加运算,但是结果会不对。

补码

为了解决反码的问题就出现了补码。

十进制原码反码补码20000 00100000 00100000 0010-21000 00101111 11011111 1110

正数的补码和原码、反码一样,负数的补码就是反码+1。

十进制原码反码补码50000 01010000 01010000 0101-31000 00111111 11001111 1101

5-3 = 5+(-3) = 0000 0101(补码) + 1111 1101(补码) = 0000 0010(补码) = 0000 0010(原码) = 2

5-3=2!!正确。

再来看特殊的:

1-1 = 1+(-1) = 0000 0001(补码) + 1111 1111(补码) = 0000 0000(补码) = 0000 0000(原码) = 0

1-1=0!!正确

再来看一个特殊的运算:

0+0 = 0000 0000(补码) + 0000 0000(补码) = 0000 0000(补码) = 0000 0000(原码) = 0

0+0=0!!也正确。

所以,我们可以看到补码解决了反码的问题。

所以对于数字,我们可以使用补码的形式来进行二进制表示。

负数位移运算

我们再来看-2 << 1与-2 >> 1。

-2用原码表示为10000000 00000000 00000000 00000010

-2用反码表示为11111111 11111111 11111111 11111101

-2用补码表示为11111111 11111111 11111111 11111110

-2 << 1,表示-2的补码左移一位后为11111111 11111111 11111111 11111100,该补码对应的反码为

11111111 11111111 11111111 11111100 - 1 = 11111111 11111111 11111111 11111011

该反码对应的原码为:符号位不变,其他位取反,为10000000 00000000 00000000 00000100,表示-4。

所以-2 << 1 = -4。

同理-2 >> 1是一样的计算方法,这里就不演示了。

无符号右移

上面在进行左移和右移时,我有一点没讲到,就是在对补码进行移动时,符号位是固定不动的,而无符号右移是指在进行移动时,符号位也会跟着一起移动。

比如-2 >>> 1。

-2用原码表示为10000000 00000000 00000000 00000010

-2用反码表示为11111111 11111111 11111111 11111101

-2用补码表示为11111111 11111111 11111111 11111110

-2的补码右移1位为:01111111 11111111 11111111 11111111

右移后的补码对应的反码、原码为:01111111 11111111 11111111 11111111 (因为现在的符号位为0,表示正数,正数的原、反、补码都相同)

所以,对应的十进制为2147483647。

也就是-2 >>> 1 = 2147483647

总结

文章写的可能比较乱,希望大家能看懂,能有所收获。这里总结一下,我们可以发现:

2 << 1 = 4 = 2*2

2 << 2 = 8 = 2*2*2

2 << n = 2*2n

m << n = m * 2n

右移则相反,所以大家以后在源码中再看到位运算时,可以参考上面的公式。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。