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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (169)

我想了解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

这里的混乱是标志说,两者都是负数。可能是我误读/误解了吗?

不知道我的问题很混乱。被迫孤立的问题:

我的问题恰恰是:正数存储在binary as is负数中时存储为two's complement

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

提问于
用户回答回答于

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

byte:字节数据类型是一个8位有符号二进制补码整数

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

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

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

float:浮点数据类型是一个单精度32位IEEE 754浮点

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

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

char: char数据类型是一个单一的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等等)。

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

用户回答回答于

Java整数是32位,并且始终签名。这意味着,最重要的位(MSB)用作符号位。由an表示的整数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中,有一个关键字unsigned(在java中不可用),可用于声明unsigned int x;。在无符号整数中,MSB的权重是正数(2^31)而不是负数。在这种情况下,an的范围unsigned int0to 2^32 - 1,而an的int范围是-2^31to 2^31 - 1

从另一个角度来看,如果你考虑xas ~x + 1(不是x加1)的二次补码,下面是解释:

对于任何x~x只是位反转x,所以只要x有一个1位,~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

扫码关注云+社区

领取腾讯云代金券