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


83

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

有人说全部都存储在二进制补码中,一个回答说只有负数被存储为二进制补码。


二进制补码必然意味着正数由该数字的实际位值表示……至少据我所知。编辑:此外,二进制补码意味着基元中的字节总数减少一位,而不是PER字节减少一位。
LJ2

您的假设是正确的:正数和负数是二进制补码,您的xy是正确的。
jlordo

附带说明:Java是一种WTF,它是Internet时代的语言,没有数据类型来表示例如。TCP / IP端口号(16位无符号值)准确,有时会导致代码非常难看。
海德

检查Wiki文章en.wikipedia.org/wiki/…您为15给出的2的补码是错误的
Dungeon Hunter

@hyde'真的很丑的代码'如?
洛恩侯爵,

Answers:


102

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

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

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

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

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

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

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

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

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

这种表示比较简单。但是,您不能以与添加十进制数相同的方式添加二进制数,这使得在硬件级别更难以实现。此外,此方法使用两个二进制模式来表示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的二进制值表示最大值。顾名思义,该值以具有偏差(通常为2 ^(n-1)或2 ^(n-1)-1)的n位二进制编码(正或负)。

因此,如果我们使用的是8位,则十进制的1值将以2 ^(n-1)的偏差用二进制表示,取值为:

+1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
converting to binary
1000 0001

2
我的问题恰恰是:+ ve数字是否存储在binary as is-ve数字中two's complement
Kevin Rave 2012年

1
正整数通常存储为简单的二进制数,负整数存储为二进制补数。
dreamcrash 2012年

那回答了我的问题。有消息来源吗?我没有找到明确说明这一点的文件。
凯文·拉夫

上面来自ecomware.com的链接已损坏@dreamcrash,您还可以提供其他吗?
拉姆·帕特拉2014年


61

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(NOT 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

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

x + ~x + 1 = 0
-x = ~x + 1

因此,您可以看到负数x可以由表示~x + 1,我们称之为的补数x


我的问题恰恰是:+ ve数字是否存储在binary as is-ve数字中two's complement
Kevin Rave 2012年

嗯,是。负数表示为计算机的正值的二进制补码。
0605002 2012年

4
很好的答案和解释Bonny @ 0605002,+1 :)
拉基布尔伊斯兰教

@ 0605002:如果可以,请提供对此答案的引用?尽管我知道这些概念,但从未真正想到过它们。最简单,仍然准确的答案。
Abhishek Singh,

大学四年了,我从不理解2s补码。这个答案教了我更多。如此可悲的是,世界各地都以这种不可思议的方式教授这种简单的事情。
Prashant Pandey

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

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


1
10的二进制补码是11111111 11111111 11111111 11110110。当二进制数为10时,您的打印结果是1010。那么,仅-ve数字被存储为二进制补码?
Kevin Rave 2012年

检查Wiki文章en.wikipedia.org/wiki/…您为15给出的2的补码是错误的
Dungeon Hunter

如果msb位以1开头,它将为负数
Dungeon Hunter

是的10的二进制补码是11111111 11111111 11111111 11110110,它是-10
Dungeon Hunter

+ ve数字将以二进制形式存储,而符号位保留为2的补码
Dungeon Hunter

4

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

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

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


3

根据该文档,所有整数都以Java的二进制补码格式进行签名和存储。不确定其可靠性..


“以二进制补码格式,正值表示为简单的二进制数。” 写在同一文档中..因此从技术上讲是正确的。:)
Shashi 2013年

3

正数按原样存储/导出。

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。因此它是否定的。和2的补码将在MSB之外执行。

  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

现在,字节转换占用了最后一个字节,即01111110。(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和(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的补码”?



2

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


1
欢迎来到StackOverflow!:D
0605002

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,因此表示的值为负。


1

正数直接以二进制形式存储。负数需要2的补语。

例如:

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

这是有符号位的差异。


1

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

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

因此,最终的答案是两个值(+ve and -ve)仅以2'补码形式存储。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.