原码补码反码和Java中整型数据的表示
Posted CodeJiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原码补码反码和Java中整型数据的表示相关的知识,希望对你有一定的参考价值。
文章目录
1. 原码、补码、反码和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 1111
加1可得
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中整型数据的表示的主要内容,如果未能解决你的问题,请参考以下文章