原码补码反码和Java中整型数据的表示

Posted CodeJiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原码补码反码和Java中整型数据的表示相关的知识,希望对你有一定的参考价值。

文章目录

1. 原码、补码、反码和Java中整型数据的表示

Java位运算如果有不太懂得地方请查看这篇博客


1.1 显示32位整数在计算机里面的状态(二进制补码)

代码:

    public static void print(int num) 
        for (int i = 31; i >= 0; i--) 
            /*
             * 1 << i
             * 如果i = 31, 1<<31 = 1000...0000(一共32位), num & 这个数相当于把 num的第32位求出来
             * 如果i = 30, 1<<30 = 0100...0000(一共32位), num & 这个数相当于把 num的第31位求出来
             * num & (1 << i) 相当于把 num的第 i + 1位求出来, 因为 0 & N = 0, 1 << i 除了第 i + 1位为1, 其余位都位都为0
             * 当num第i位为0时,  num & (1 << i) = 0
             * 当num第i位为1时, num & (1 << i) = 1
             */
            System.out.print((num & (1 << i)) == 0 ? "0" : "1");
        
        System.out.println();
    

运行结果:


1.2 Java中32位整数(int)的表示

在Java中 32位的整数的表示范围是 -231 ~ 231 - 1(其中负数占了一半,非负数占了一半),最高位(32位)表示数字的符号,其中0表示整数,1表示负数。

比如:-231 转为10进制为-2147483648,在计算机内部为:

232转为10进制为2147483647,在计算机内部为:


1.3 原码、补码、反码

原码:

原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值,例如的十进制的的正负1,用8位二进制的原码表示如下:

  • 【+1】= 原:0000 0001
  • 【-1】 = 原:1000 0001

反码:

正数的反码是其原码本身。
负数的反码是在其原码的基础上,符号位不变,其余各位取反。

  • 【+1】= 原: 0000 0001 = 反: 0000 0001
  • 【-1】 = 原: 1000 0001 = 反: 1111 1110

补码:

正数的补码是其原码本身。
负数的补码是在其原码的基础上,符号位不变,其余各位取反后加1(即在反码的基础上加1)。

  • 【+1】= 原: 0000 0001 = 反:0000 0001 = 补:0000 0001

  • 【-1】 = 原:1000 0001 = 反:1111 1110 = 补: 1111 1111


1.4 数据在计算机中的存储形式

计算机只存储补码,在原、反、补码中,正数的表示是一模一样的,而负数的表示是不相同的,所以对于负数的补码来说,我们是不能直接用进制转换将其转换为十进制数值的,因为这样是得不到计算机真正存储的十进制数的,所以应该将其转换为原码后,再将转换得到的原码进行进制转换为十进制数。(机器数包含符号位)


1.5 为什么计算机底层选择存储补码

计算机是不能直接做减法运算的,因为普通电脑硬件中没有减法器,不需要额外的增加硬件电路制造难度,减法器无需存在。但可以优雅的转换成减法

数据在内存里以补码的形式存储是为了简化计算机的结构设计,同时也提高了运算速度。

如何计算?1314 - 520可以转换成1314 + (-520),就这么简单。

1314的补码:0000 0101 0010 0010
-520的补码:1111 1101 1111 1000
  相加可得: 0000 0011 0001 1010  (最高位的1直接溢出不用管, 这样就实现了加法和减法都使用加法的逻辑)  

计算机没有减法概念,不代表没有负数的概念。

计算机中的负数为了方便运算,所以计算机才会采用补码(正数的补码和反码就是原码)存储数据。

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。


1.6 负号号可用取反加一表示(计算机底层负号的原理)

解释:(注意取反(~)是对补码进行取反,因为计算机存储的是补码)

1314 的补码:0000 0101 0010 0010
1314 的取反:1111 1010 1101 1101
取反+1可以表示为:
1111 1010 1101 1101
0000 0000 0000 0001
-------------------
1111 1010 1101 1110 即为:-1314的补码

-520 的补码:1111 1101 1111 1000
-520 的取反:0000 0010 0000 0111
取反+1可以表示为:
0000 0010 0000 0111
0000 0000 0000 0001
-------------------
0000 0010 0000 1000 即为:520的补码

1.7 分享一个小发现

package chapter01;

class Solution 
    public static void main(String[] args) 
        System.out.println(Integer.MIN_VALUE);
        System.out.println(-Integer.MIN_VALUE);
        System.out.println(~Integer.MIN_VALUE + 1);
        print(Integer.MIN_VALUE);
        System.out.println("=====================");
        System.out.println(Integer.MIN_VALUE + 1);
        System.out.println(~(Integer.MIN_VALUE + 1) + 1);
        print(Integer.MIN_VALUE + 1);
    

    public static void print(int num) 
        for (int i = 31; i >= 0; i--) 
            /*
             * 1 << i
             * 如果i = 31, 1<<31 = 1000...0000(一共32位), num & 这个数相当于把 num的第32位求出来
             * 如果i = 30, 1<<30 = 0100...0000(一共32位), num & 这个数相当于把 num的第31位求出来
             * num & (1 << i) 相当于把 num的第 i + 1位求出来, 因为 0 & N = 0, 1 << i 除了第 i + 1位为1, 其余位都位都为0
             * 当num第i位为0时,  num & (1 << i) = 0
             * 当num第i位为1时, num & (1 << i) = 1
             */
            System.out.print((num & (1 << i)) == 0 ? "0" : "1");
        
        System.out.println();
    

上面代码的运行结果如下:

我们来说明原因:

Integer.MIN_VALUE = -2147483648
在计算机内部表示为: 
1000 0000 0000 0000 0000 0000 0000 0000
取反后(~0111 1111 1111 1111 1111 1111 1111 11111可得
 0111 1111 1111 1111 1111 1111 1111 1111
+0000 0000 0000 0000 0000 0000 0000 0001
----------------------------------------
 1000 0000 0000 0000 0000 0000 0000 0000

1.8 关于取反和反码的区别


1.8.1 位取反(~)运算

位取反运算符为~,其运算规则是:只对一个操作数进行运算,将操作数二进制中的 1 改为 0,0 改为 1。

示例

  1 1 0 1 0
--------------
~ 0 0 1 0 1

示例:


1.8.2 反码

正数的反码是其原码本身。
负数的反码是在其原码的基础上,符号位不变,其余各位取反。

  • 【+1】= 原: 0000 0001 = 反: 0000 0001
  • 【-1】 = 原: 1000 0001 = 反: 1111 1110

1.8.3 区别

位取反(~) 操作是针对于补码(计算机里面存储的是补码)。
反码操作是针对于原码。



以上是关于原码补码反码和Java中整型数据的表示的主要内容,如果未能解决你的问题,请参考以下文章

原码补码反码和Java中整型数据的表示

原码反码补码,负数表示法

原码,补码,反码

正数和负数的原码反码补码及二进制位运算

计算机的,反码,原码,补码!求它们的计算方法

原码反码补码详解