在 Java 中,整数如何在位级别内部表示?

2022-08-31 11:35:32

我试图理解Java如何在内部存储整数。我知道所有的java原始整数都是有符号的,(除了短的?)。这意味着该数字的字节中可用的位少了一个位。

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

我看到规格上写着.但我经常感到困惑。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

这里的混乱再次是符号说,两者都是负数。可能是我误读了/误解了它?

编辑不确定我的问题是否令人困惑。被迫隔离问题:

我的问题恰恰是:正数是否按原样存储在二进制中,而负数则存储为二进制补码

有人说,所有这些都存储在二的补码中,一个答案说只有负数被存储为二的补码。


答案 1

让我们从总结 Java 基元数据类型开始:

byte:Byte 数据类型是 8 位有符号二进制的补码整数

Short:Short 数据类型是 16 位有符号的 2 的补码整数

整型:Int 数据类型是 32 位有符号二进制的补码整数

长:长整型数据类型是 64 位有符号二进制的补码整数

浮:浮点数据类型是单精度 32 位 IEEE 754 浮点。

double:double 数据类型是双精度 64 位 IEEE 754 浮点。

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

char:char 数据类型是单个 16 位 Unicode 字符

二的补体

“一个很好的例子来自wiki,通过指出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、-0 (1000)+0 (0000)。

2. 一个人的补体

在这种表示中,我们反转给定数字的所有位以找出其互补性。例如:

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

这种表示的问题在于,仍然存在两个位模式来表示0,负0(1111)正0(0000)

3. 二人补码

为了找到一个数字的负数,在这个表示中,我们反转所有位,然后添加一个位。添加一个位解决了具有两个表示 0 的位模式的问题。在此表示中,我们只有一个 0 (0000) 的模式。

例如,我们希望使用 4 位查找 4(十进制)的二进制负表示。首先,我们将 4 转换为二进制:

4 = 0100

然后我们反转所有位

0100 -> 1011

最后,我们添加一位

1011 + 1 = 1100.

因此,如果我们使用4位的Two的补码二进制表示,则1100相当于十进制中的-4。

找到互补的更快方法是将第一个位固定为值1并反转其余位。在上面的示例中,它将是这样的:

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

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

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

答案 2

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

所以,二者的补码并不是表示负整数的排他方案,相反,我们可以说整数的二进制表示总是相同的,我们只是否定了最有效位的权重。该位决定了整数的符号。

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

从另一个角度来看,如果你考虑两者的补码as(不是x加一),这里有一个解释:x~x + 1

对于任何 ,只是 的按位逆,所以只要有 -bit,就会有 -bit(反之亦然)。因此,如果将这些相加,加法中将没有携带,并且总和将只是一个整数,其中每个位都是。x~xxx1~x01

对于 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

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

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

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


推荐