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

新手上路,请多包涵

我试图了解 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

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

原文由 Kevin Rave 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 390
2 个回答

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

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

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

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

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

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

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

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

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 位的二进制补码表示形式,则 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

原文由 dreamcrash 发布,翻译遵循 CC BY-SA 4.0 许可协议

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中有一个关键字 unsigned (java中没有),可以用来声明 unsigned int x; 。在无符号整数中,MSB 的权重是正数 ( 2^31 ) 而不是负数。 In that case the range of an unsigned int is 0 to 2^32 - 1 , while an int has range -2^31 to 2^31 - 1

从另一个角度来看,如果您将 x 的补码视为 ~x + 1 (不是 x 加一),这里是解释:

For any x , ~x is just the bitwise inverse of x , so wherever x has a 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 的补码。

原文由 Sufian Latif 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题