首页 文章

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

提问于
浏览
72

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

Edit

要清楚, 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

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

Edit 不确定我的问题是否令人困惑 . 被迫隔离问题:

My question precisely: Are positive numbers stored in binary as is while negative numbers are stored as two's complement?

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

10 回答

  • 2

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

    例如,使用1个字节(= 2个半字节= 8位),十进制数5由0000 01012表示 . 最高有效位为0,因此模式表示非负值 . 要以二进制补码表示法转换为-5,这些位将被反转; 0变为1,1变为0:1111 1010此时,数字是十进制值-5的补码 . 为了获得二进制补码,将1添加到结果中,给出:1111 1011结果是一个带符号的二进制数,表示二进制补码形式的十进制值-5 . 最重要的位是1,因此表示的值为负 .

  • 2

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

    byte :字节数据类型是8位有符号 two's complement integer .

    Short :短数据类型是16位有符号 two's complement integer .

    int: Int数据类型是32位签名的 two's complement integer .

    long: 长数据类型是64位有符号 two's complement integer .

    float: Float数据类型是单精度 32-bit IEEE 754 floating point .

    double :double数据类型是双精度 64-bit IEEE 754 floating point .

    boolean: 布尔数据类型表示 one bit of information .

    char: char数据类型是 single 16-bit Unicode character .

    Source

    Two's complement

    “好的例子是从wiki那个关系到两个's complement is realized by noting that 256 = 255 + 1, and (255 − x) is the ones'的补充

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

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

    -7 = 1001 = -8 0 0 1

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

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

    Source

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

    更详细的答案:

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

    • 签名幅度

    • 一个补充

    • 两个补充

    • 偏见

    1. Signed Magnitude

    使用最高有效位表示符号,其余位用于表示绝对值 . 0 表示 positive number1 表示 negative number ,例如:

    1011 = -3
    0011 = +3
    

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

    2. One's Complement

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

    010 = 2, so -2 = 101 (inverting all bits).
    

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

    3. Two's Complement

    要找到数字的负数,在此表示中,我们将所有位反转,然后添加一位 . 添加一位解决了两位模式表示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. Bias

    该表示用于表示浮点数的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
    
  • 2

    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加1),这里是解释:

    对于任何 x~x 只是 x 的按位反转,所以只要 x 具有 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 -bit将被丢弃,因为它不适合32位(整数溢出) . 所以,

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

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

  • 56

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

    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
    

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

  • 86

    Oracle提供了一些有关Java Datatypes的文档,您可能会感兴趣 . 特别:

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

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

  • 3

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

  • 10

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

  • 1

    原始数字按原样存储/恢复 .

    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
    

    Diff(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.
    

    参考文献

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

    What is “2's Complement”?

  • 1

    正数直接存储为二进制数 . 负数需要2的恭维 .

    例如:

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

    这是签名位的区别 .

  • 4

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

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

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

相关问题