86

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

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

我看到规格说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

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

4

10 回答 10

111

让我们从总结 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
于 2012-11-16T18:36:48.533 回答
62

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^31是 to 2^31 - 1

从另一个角度来看,如果您考虑xas ~x + 1(NOT x plus one) 的二进制补码,以下是解释:

对于任何x,~x只是 的按位倒数x,所以凡x1-bit 的地方,~x都会有0-bit (反之亦然)。所以,如果你把这些加起来,加法中不会有进位,总和只是一个整数,其中的每一位都是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

于 2012-11-16T18:39:45.940 回答
10

我已经运行了以下程序来了解它

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

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

于 2012-11-16T18:36:36.930 回答
5

Oracle 提供了一些您可能会感兴趣的有关 Java数据类型的文档。具体来说:

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

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

于 2012-11-16T18:35:49.067 回答
4

正数按原样存储/检索。

e.g) 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的补码”?

于 2015-02-12T13:23:02.310 回答
3

根据this document,所有整数都以java的二进制补码格式进行签名和存储。不确定它的可靠性..

于 2012-11-16T18:34:23.527 回答
3

最高有效位(第 32 位)表示该数字是正数还是负数。如果为 0,则表示该数为正数,并以其实际二进制表示形式存储。但如果为 1,则表示该数为负数,并以二进制补码表示形式存储。因此,当我们将权重 -2^32 赋予第 32 位,同时从其二进制表示中恢复整数值时,我们得到了实际答案。

于 2012-11-16T18:51:32.727 回答
2

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

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

0000 01012 最高有效位为 0,因此该模式表示非负值。要以二进制补码表示法转换为 -5,请反转位;0变成1,1变成0:

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

1111 1011 结果是一个有符号二进制数,表示二进制补码形式的十进制值 -5。最高有效位为 1,因此表示的值为负数。

于 2015-01-09T14:01:20.070 回答
2

正数直接存储为二进制。负数需要 2 的补码。

例如:

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

这是有符号位的差异。

于 2014-02-07T06:59:52.333 回答
1

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

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

所以最终的答案是这两个值(+ve and -ve)都只以 2' 补码形式存储。

于 2016-12-27T17:14:14.220 回答