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

时间:2012-11-16 18:22:41

标签: java memory binary store twos-complement

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

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

10 个答案:

答案 0 :(得分:87)

让我们首先总结一下Java原始数据类型:

字节:字节数据类型是8位带符号的二进制补码整数

:短数据类型是16位带符号的二进制补码整数

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

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

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

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

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

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

Source

两个补充

“好的例子来自wiki,通过注意256 = 255 + 1来实现与两个补码的关系,并且(255 - x)是x的补码

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

它的工作方式是MSB(最重要的位)收到负值,所以在上面的情况

  

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

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

负整数存储为其绝对值的二进制补码。正数的两个补码是使用这个表示法时的负数。

Source

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

更详细的答案:

其中有四种主要方法用二进制表示正数和负数,即:

  1. 签名幅度
  2. One's Complement
  3. Two's Complement
  4. 偏置
  5. <强> 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。两个补语

    要查找数字的负数,在此表示中,我们将所有位反转,然后添加一位。添加一位解决了两位模式表示0的问题。在此表示中,我们只有一个(00 ... 0)。

    例如,我们希望使用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
    

答案 1 :(得分:56)

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)而不是负数。在这种情况下,unsigned int的范围是02^32 - 1,而int的范围是-2^312^31 - 1

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

对于任何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的两个补码。

答案 2 :(得分: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

从输出看起来它似乎一直在使用两个补码。

答案 3 :(得分:4)

Oracle提供了一些您可能感兴趣的有关Java Datatypes的文档。具体做法是:

  

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

顺便说一下,short也存储为两个补码。

答案 4 :(得分:3)

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

答案 5 :(得分:2)

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

答案 6 :(得分:2)

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

  

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

表示      

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

     

1111 1010此时,数字是&#39;补充的   小数值-5。为了获得两个补码,将1添加到   结果,给出:

     

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

答案 7 :(得分:2)

  

按原样存储/重试正数。

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转换为byte时,只会考虑最后一个字节以及最后一个字节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)之间的差异(字符)-1和(int)(短)(字节)-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. 
  

参考

Why is two's complement used to represent negative numbers?

What is “2's Complement”?

答案 8 :(得分:1)

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

例如:

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

这是有符号位的区别。

答案 9 :(得分:1)

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

仅对于负整数,我们计算2&#39;补码值(-14= 10001+1 = 10010)

因此,最终答案是值(+ve and -ve)仅以2&#39;补码形式存储。