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

Kev*_*ave 80 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
Run Code Online (Sandbox Code Playgroud)

编辑

要清楚, x = 15

   In binary as is: `00000000 00000000 00000000 00001111'
  Two's complement: `11111111 11111111 11111111 11110001`
Run Code Online (Sandbox Code Playgroud)

因此,如果您的答案是 all数字存储为两个补码,那么:

  int x = 15; // 11111111 11111111 11111111 11110001
  int y = -22 // 11111111 11111111 11111111 11101010
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

dre*_*ash 94

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

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

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

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

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

float: 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,依此类推).

负整数存储为其绝对值的二进制补码.正数的两个补码是使用这个符号时的负数.

资源

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

一个更详细的答案:

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

  1. 签名量
  2. 一个人的补充
  3. 两个人的补充
  4. 偏压

1.签名量

使用最高有效位表示符号,其余位用于表示绝对值.其中0表示正数,1表示负数,例如:

1011 = -3
0011 = +3
Run Code Online (Sandbox Code Playgroud)

这种表示更简单.但是,您不能以添加十进制数的方式添加二进制数,这使得在硬件级别实现更难.此外,该方法使用两个二进制模式来表示0,100 ... 0和0 .... 0.

2.一个人的补充

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

010 = 2, so -2 = 101 (inverting all bits).
Run Code Online (Sandbox Code Playgroud)

这种表示的问题是仍然存在两个位模式来表示0(00..0和11..1)

3.两个补充

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

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

4 = 0100
Run Code Online (Sandbox Code Playgroud)

然后我们反转所有的比特

0100 -> 1011
Run Code Online (Sandbox Code Playgroud)

最后,我们加一点

1011 + 1 = 1100.
Run Code Online (Sandbox Code Playgroud)

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

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

0100 -> 1100
^^ 
||-(fixing this value)
|--(inverting this one)
Run Code Online (Sandbox Code Playgroud)

两个补语表示,除了只有一个0的表示,它还以十进制相同的方式添加两个二进制值,偶数具有不同的符号.然而,有必要检查溢出情况.

偏见

该表示用于表示浮点数的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
Run Code Online (Sandbox Code Playgroud)

  • 我的问题是:+ +数字存储在`binary as as`中,而-ve数存储在`two'scomple`中? (2认同)

060*_*002 57

Java整数是32位,并且始终是有符号的.这意味着,最高有效位(MSB)用作符号位.由a表示的整数int只是位的加权和.权重分配如下:

Bit#    Weight
31      -2^31
30       2^30
29       2^29
...      ...
2        2^2
1        2^1
0        2^0
Run Code Online (Sandbox Code Playgroud)

注意,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
Run Code Online (Sandbox Code Playgroud)

所以,这两个补码不是表示负整数的排他方案,而是我们可以说整数的二进制表示总是相同的,我们只是否定最重要位的权重.该位确定整数的符号.

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

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

对于任何x,~x只是按位反转x,所以无论哪里x有一个1-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
Run Code Online (Sandbox Code Playgroud)

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

x + ~x + 1 = 0
-x = ~x + 1
Run Code Online (Sandbox Code Playgroud)

所以你可以看到负数x可以用~x + 1,我们称之为二的补码x.

  • 很棒的答案和解释Bonny @ 0605002,+ 1 :) (4认同)

Dun*_*ter 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是

1010
11111111111111111111111111110110
Run Code Online (Sandbox Code Playgroud)

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


mat*_*sev 5

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

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

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