在Java中,整数是如何内部表示的?

我想了解Java如何在内部存储整数。 我知道所有的Java原始整数签名,(除短吗?)。 这意味着数字的一个字节中less了一位。

我的问题是,所有的整数(正数和负数)存储为二进制补码还是只有负数的二进制补码?

我看到规格说x bit two's complement number 。 但是我经常感到困惑。

例如:

  int x = 15; // Stored as binary as is? 00000000 00000000 00000000 00001111? int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010 

编辑

要清楚, x = 15

  In binary as is: `00000000 00000000 00000000 00001111' Two's complement: `11111111 11111111 11111111 11110001` 

所以如果你的答案是all数字都被存储为二进制补码,那么:

  int x = 15; // 11111111 11111111 11111111 11110001 int y = -22 // 11111111 11111111 11111111 11101010 

这里的混淆再次是标志说,都是负数。 可能是我误读/误解了吗?

编辑不知道我的问题是混乱。 被迫孤立的问题:

我的问题恰恰是:正数以binary as isforms存储,而负数以binary as isforms存储?

有人说所有的都是二进制补码,一个答案只有负数存储为二进制补码。

让我们从总结Java原始数据types开始:

字节 :字节数据types是一个8位有符号的二进制补码整数

Short :短数据types是一个16位有符号的二进制补码整数

int: Int数据types是一个32位有符号的二进制补码整数

long: long数据types是一个64位有符号的二进制补码整数

float: Float数据types是一个单精度的32位IEEE 754浮点数

double :double数据types是一个双精度的64位IEEE 754浮点数

布尔值:布尔型数据types表示一位信息

char: char数据types是一个16位的Unicode字符

资源

两个补码

“ 维基的一个很好的例子是,与二进制补码的关系是通过注意到256 = 255 + 1来实现的,(255-x)是x的补码

0000 0111 = 7二进制补码是1111 1001 = -7

它的工作方式是msb(最高有效位)在上面的情况下收到一个负值

-7 = 1001 = -8 + 0 + 0 + 1

通常将正整数存储为简单的二进制数(1是1,10是2,11是3等等)。

负整数作为其绝对值的二进制补码存储。 当使用这个符号时,正数的二进制补码是负数。

资源

由于我收到了这个答案的几点,我决定添加更多的信息。

更详细的答案:

除了其他之外,还有四种主要方法来表示二进制的正数和负数,即:

  1. 签名幅度
  2. 一个人的补充
  3. 两个的补充
  4. 偏压

1.签名幅度

使用最高有效位来表示符号,其余位用来表示绝对值。 其中0表示正数1表示负数 ,例如:

 1011 = -3 0011 = +3 

这种表示更简单。 但是,不能像添加十进制数字那样添加二进制数字,因此难以在硬件级别实现。 此外,这种方法使用两个二进制模式来表示0,100 … 0和0 …. 0。

2.补货

在这个表示中,我们反转给定数字的所有位以找出它的互补。 举个例子:

 010 = 2, so -2 = 101 (inverting all bits). 

这种表示的问题是仍然存在两个比特模式来表示0(00..0和11..1)

3.两个人的补充

为了find一个数的负数,在这个表示中,我们将所有的位反转,然后添加一位。 加一位解决了两个位模式代表0的问题。在这个表示中,我们只有一个(00 … 0)。

例如,我们想用4位find4(十进制)的二进制负表示。 首先我们将4转换成二进制:

 4 = 0100 

然后我们倒置所有的位

 0100 -> 1011 

最后我们加一点

 1011 + 1 = 1100. 

所以如果我们使用4位的Two's Complement二进制表示,那么1100相当于十进制的-4。

find互补的更快的方法是将第一位固定为值1并反转剩余的位。 在上面的例子中,它会是这样的:

 0100 -> 1100 ^^ ||-(fixing this value) |--(inverting this one) 

二的补码表示法,除了只有一个0的表示forms外,还以与十进制数相同的方式添加了两个二进制数值,即不同符号的偶数。 不过,有必要检查溢出情况。

4.偏见

这个表示用于表示浮点的IEEE 754标准的指数。 它的优点是所有位的二进制值都为零表示最小的值。 而所有位的二进制值为1表示最大值。 正如名字所表示的那样,该值以二进制编码(正值或负值),n位有偏差(通常为2 ^(n-1)或2 ^(n-1)-1)。

所以如果我们使用8位,那么十进制中的值1用2 ^(n-1)的偏差以二进制表示,其值为:

 +1 + bias = +1 + 2^(8-1) = 1 + 128 = 129 converting to binary 1000 0001 

Java整数是32位,并始终签名。 这意味着,最重要的位(MSB)作为符号位。 int表示的整数不过是比特的加权和。 权重分配如下:

 Bit# Weight 31 -2^31 30 2^30 29 2^29 ... ... 2 2^2 1 2^1 0 2^0 

请注意,MSB的权重为负数(实际上可能是最大的负数),所以当此位打开时,整数(加权和)变为负数。

让我们用4位数字来模拟它:

 Binary Weighted sum Integer value 0000 0 + 0 + 0 + 0 0 0001 0 + 0 + 0 + 2^0 1 0010 0 + 0 + 2^1 + 0 2 0011 0 + 0 + 2^1 + 2^0 3 0100 0 + 2^2 + 0 + 0 4 0101 0 + 2^2 + 0 + 2^0 5 0110 0 + 2^2 + 2^1 + 0 6 0111 0 + 2^2 + 2^1 + 2^0 7 -> the most positive value 1000 -2^3 + 0 + 0 + 0 -8 -> the most negative value 1001 -2^3 + 0 + 0 + 2^0 -7 1010 -2^3 + 0 + 2^1 + 0 -6 1011 -2^3 + 0 + 2^1 + 2^0 -5 1100 -2^3 + 2^2 + 0 + 0 -4 1101 -2^3 + 2^2 + 0 + 2^0 -3 1110 -2^3 + 2^2 + 2^1 + 0 -2 1111 -2^3 + 2^2 + 2^1 + 2^0 -1 

所以,这两个补码不是一个表示负整数的排他scheme,相反我们可以说整数的二进制表示总是相同的,我们只是否定了最重要的位的权重。 那一点决定了整数的符号。

在C中,有一个关键字unsigned (在java中不可用),可以用来声明unsigned int x; 。 在无符号整数中,MSB的权重是正的( 2^31 ),而不是负的。 在这种情况下, unsigned int的范围是02^32 - 1 ,而int范围是-2^312^31 - 1

从另一个angular度来看,如果把x的二进制补码看作~x + 1 (不是x加1),下面是解释:

对于任何x ,〜x只是~x的位逆,所以当x1位时,〜x将有0位(反之亦然)。 所以,如果将这些加起来,那么在加法中就不会有任何进位,并且和将只是一个整数,每一位都是1

对于32位整数:

 x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111 x + ~x + 1 = 1111 1111 1111 1111 1111 1111 1111 1111 + 1 = 1 0000 0000 0000 0000 0000 0000 0000 0000 

最左边的1位将被丢弃,因为它不适合32位(整数溢出)。 所以,

 x + ~x + 1 = 0 -x = ~x + 1 

所以你可以看到,负x可以用~x + 1来表示,我们称之为x的二的补码。

我运行了下面的程序来了解它

 public class Negative { public static void main(String[] args) { int i =10; int j = -10; System.out.println(Integer.toBinaryString(i)); System.out.println(Integer.toBinaryString(j)); } } 

输出是

 1010 11111111111111111111111111110110 

从输出看来,它一直在使用二进制补码。

Oracle提供了一些关于Java 数据types的文档,您可能会感兴趣。 特别:

int:int数据types是一个32位有符号的二进制补码整数。 最小值为-2,147,483,648,最大值为2,147,483,647(含)。

顺便说一句,短也存储为二进制补码。

根据这个文档 ,所有的整数都是以java的二进制补码格式进行签名和存储的。 不确定其可靠性..

最高有效位(32位)表示数字是正数或负数。 如果是0,则表示数字是正数,并以实际的二进制表示forms存储。 但是如果是1,则表示该数字是负数,并以其二进制补码表示存储。 所以当我们把第二十二位的权值-2 ^ 32从二进制表示中恢复出来的时候,我们得到了实际的答案。

谢谢你, dreamcrash的答案https://stackoverflow.com/a/13422442/1065835 ; 在维基页面上,他们给出了一个例子,帮助我理解如何找出正数的负数的二进制表示。

例如,使用1个字节(= 2个半字节= 8个比特),十进制数5表示为

0000 01012最重要的位是0,所以模式代表一个非负值。 要用二进制表示法转换为-5,这些位是相反的; 0变成1,1变成0:

1111 1010此时,数字是十进制值-5的补码。 为了得到二的补码,将1加到结果中,给出:

1111 1011结果是一个带符号的二进制数,代表二进制补码forms的十进制值-5。 最重要的位是1,所以表示的值是负的。

正数直接存储为二进制。 2的赞美是负数的要求。

例如:

15:00000000 00000000 00000000 00001111
-15:11111111 11111111 11111111 11110001

这里是有符号位的区别。

正数将按原样保存/修改。

 eg) For +ve number 10; byte representation will be like 0-000 0010 (0 - MSB will represent that it is +ve). So while retrieving based on MSB; it says it is +ve, so the value will be taken as it is. 

但是在2的补码(MSB位除外)之后将存储负数,MSB位将设置为1。

例如)当存储-10时

  0-000 0010 -> (1's complement) -> 0-111 1101 -> (2's complement) 0-111 1101 + 1 -> 0-111 1110 Now MSB will be set to one, since it is negative no -> 1-111 1110 

当检索时,它发现MSB被设置为1.所以它是否定的。 除了MSB以外,还会执行2的补码。

  1-111 1110 --> 1-000 0001 + 1 --> 1-000 0010 Since MSB representing this is negative 10 --> hence -10 will be retrived. 

铸件

还要注意的是,当你将int / short转换为字节时,只有最后一个字节会与最后一个字节MSB一起被考虑,

以“-130”为例,可以像下面那样存储

 (MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110 

现在字节转换最后一个字节是0111 1110.(0-MSB)由于MSB表示它是+ ve值,所以它将被视为原样。 这是126.(+ ve)。

再举一个例子“130”,可能像下面那样存储

  0-000 000 1000 0010 (MSB = 0) 

现在字节转换最后一个字节是1000 0010。 (1 = MSB)由于MSB表示它是-ve值,所以将执行2的补码并返回负数。 所以在这种情况下,-126将被返回。

  1-000 0010 -> (1's complement) -> 1-111 1101 -> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110 = -126 

(int)(char)(byte)-1 AND(int)(short)(byte)-1之间的差异

 (byte)-1 -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111 (char)(byte)-1 -> 1-111 1111 1111 1111 (sign bit is carry forwarded on left) 

同样

 (short)(byte)-1-> 1-111 1111 1111 1111 (sign bit is carry forwarded on left) 

 (int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111 = 65535 since char is unsigned; MSB won't be carry forwarded. 

 (int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1 since short is signed; MSB is be carry forwarded. 

参考

为什么补码用来表示负数?

什么是“2的补充”?

对于正整数2,补偿值与MSB位0相同(like +14 2'complement is 01110)

对于只有负整数,我们正在计算2'complement值(-14= 10001+1 = 10010)

所以最后的答案是两个值(+ve and -ve)仅以2'complementforms存储。