【问题标题】:Why is 1 plus 31 zeros not a valid integer, if bit flags are 31 length, plus one negative/positive flag?如果位标志的长度为 31,加上一个负/正标志,为什么 1 加 31 个零不是有效整数?
【发布时间】:2014-04-24 03:18:32
【问题描述】:

根据this,在第一个表格下方的第四段左右,说

一般来说,我们将使用一个整数来表示域上最多 32 个值(或 64 个,使用 64 位整数)的集合,其中 1 位表示存在的成员,0 位表示一那是不存在的。

如果是这样,那为什么这个 32 位二进制数会超过Integer.MAX_VALUE

System.out.println(Integer.parseInt("10000000000000000000000000000000", 2));

错误:

Exception in thread "main" java.lang.NumberFormatException: For input string: 
"10000000000000000000000000000000"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at Test.main(Test.java:10)

【问题讨论】:

  • Integer.MAX_VALUE 是 2^^31 - 1,而您的数字又是 1,即 2^^31。对于有符号整数,最高位表示它是负数。这就是二进制补码的工作原理。

标签: java int bit-manipulation


【解决方案1】:

在底数 2 中,10000000000000000000000000000000(即 31 个零)是 2^31。 Java int 是 -2^31 和 2^31-1 之间数字的 32 位二进制补码表示;这个范围当然不包括 2^31。这就是为什么这个值不能转换为int - 尽管long 可以。

如果您有一个 Java int,其位为 10000000000000000000000000000000(仍然是 31 个零),则为 -2^31。

Java int 的第一位不是正/负标志。它只是一个位值为-2^31的数字。

【讨论】:

    【解决方案2】:

    它超过了Integer.MAX_VALUE,因为它确实超过了Integer.MAX_VALUE。是Integer.MAX_VALUE + 1,你绝对可以在int-space 中计算,你可以写成0x80000000Integer.MIN_VALUE,但它会是负数。

    这就是parseInt 抱怨的原因。

    你不能那样解析它——你可以绝对表示一个位向量,其中第 32 位设置为int。 “符号位”(这是一个误导性的名称,但我们似乎被它所困扰)只是一个普通的位,就像任何其他位一样。它的特殊含义只对:

    • 与字符串相互转换
    • 转换为更宽或浮点类型
    • 除法和余数
    • 右移,见>> vs >>>
    • 除相等外的比较,例如1 > 0x80000000。您可以比较long xy,就好像它们没有与(x ^ Long.MIN_VALUE) < (y ^ Long.MIN_VALUE) 签名一样(对于int,您可以转换为long 并使用0xffffffffL 进行掩码)

    “符号位”只是另一个没有特殊含义的位:

    • 加法和减法
    • 按位运算(包括左移)
    • 乘法
    • 平等测试
    • 转换为更窄的类型

    如果您将int 解释为位向量,“符号位”将只是一个普通位,但您必须注意您对其执行的所有操作都同意这一点。

    【讨论】:

      【解决方案3】:

      原答案:


      我想通了。 This网页为我清理了它:

      Java 整数是 32 位的。最高位保留用于加号或减号。因此您可以设置/取消设置 31 个一位标志

      我的误解是位标记使用整数中的第 32 位以这种方式作为负或正标记,好像它是这样做的一个选项 .但是Java以这种方式定义了一个整数,所以它不是一个选项——它是该定义的结果或副产品。整数只有 31 位表示数字本身。第 32 位是加减号。

      (写完之后,我发现说“位标志使用”任何东西都没有意义。位标志是概念,整数是具体类型。)


      更新:一些观察:

      Integer.MIN_VALUE 等于 -2147483648,二进制是

      10000000000000000000000000000000
      

      第一位表示否定。 在这种情况下是一个符号位,因为这是一个有符号整数(Integer.MIN_VALUE 是负数,最小值和最大值与零等距)。如果它是一个无符号整数,它只是另一个值位。

      http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html:

      签名:

      int:默认情况下,int数据类型为32位有符号二进制补码整数,最小值为-231,最大值为231-1。

      无符号:

      在 Java SE 8 及更高版本中,您可以使用 int 数据类型来表示一个无符号的 32 位整数,其最小值为 0,最大值为 232-1。使用 Integer 类将 int 数据类型用作无符号整数。有关更多信息,请参阅数字类部分。在 Integer 类中添加了 compareUnsigned、divideUnsigned 等静态方法,以支持无符号整数的算术运算。

      再次声明:Integer.MIN_VALUE 等于 -2147483648,在二进制中是

      10000000000000000000000000000000
      

      将该“符号位”更改为零不会使2147483648 (Integer.MAX_VALUE)。成功了

      00000000000000000000000000000000
      

      这是Integer.MAX_VALUE 二进制是

      01111111111111111111111111111111
      

      将“符号位”切换为 1 不会使其成为 MIN_VALUE

      11111111111111111111111111111111
      

      尝试解析失败,因为 32 位对于有符号整数的值部分来说太大了:

      System.out.println(Integer.parseInt("10000000000000000000000000000000", 2));
      

      错误:

      Exception in thread "main" java.lang.NumberFormatException: For input string: 
      "10000000000000000000000000000000"
          at java.lang.NumberFormatException.forInputString(Unknown Source)
          at java.lang.Integer.parseInt(Unknown Source)
          at Test.main(Test.java:10)
      

      相当

      11111111111111111111111111111111
      

       1111111111111111111111111111111
      

      带有表示否定的“符号位”。一个有 32 个 1 的二进制数字是 -1。我现在想不通为什么。我也不知道如何解析负(有符号)二进制文件。这个

      Integer.parseInt("-1111111111111111111111111111111", 2)
      

      等于

         num:   -2147483647
                10000000000000000000000000000001
      

      所以它是溢出或什么的......

      测试类:

      public class BinaryNumberTest  {
        public static final void main(String[] ignored)  {
           testNum(Integer.parseInt("-1111111111111111111111111111111", 2), "-1111111111111111111111111111111");
           testNum(Integer.MAX_VALUE, "Integer.MAX_VALUE");
           testNum(0, "0");
           testNum(Integer.MIN_VALUE, "Integer.MIN_VALUE");
        }
        private static final void testNum(int num, String description)  {
           System.out.println(description + ": " + num);
           System.out.println();
      
           int numMinus1 = num - 1;
           System.out.println("   num-1: " + numMinus1);
           System.out.println("          " + get32BitZeroPaddedBinaryNum(numMinus1));
      
           System.out.println("   num:   " + num);
           System.out.println("          " + get32BitZeroPaddedBinaryNum(num));
      
           int numPlus1 = num + 1;
           System.out.println("   num+1: " + numPlus1);
           System.out.println("          " + get32BitZeroPaddedBinaryNum(numPlus1));
           System.out.println();
        }
      
        private static final String get32BitZeroPaddedBinaryNum(int num)  {
           return  String.format("%32s", Integer.toBinaryString(num)).replace(' ', '0');
        }
      }
      

      输出:

      -1111111111111111111111111111111: -2147483647
      
         num-1: -2147483648
                10000000000000000000000000000000
         num:   -2147483647
                10000000000000000000000000000001
         num+1: -2147483646
                10000000000000000000000000000010
      
      Integer.MAX_VALUE: 2147483647
      
         num-1: 2147483646
                01111111111111111111111111111110
         num:   2147483647
                01111111111111111111111111111111
         num+1: -2147483648
                10000000000000000000000000000000
      
      0: 0
      
         num-1: -1
                11111111111111111111111111111111
         num:   0
                00000000000000000000000000000000
         num+1: 1
                00000000000000000000000000000001
      
      Integer.MIN_VALUE: -2147483648
      
         num-1: 2147483647
                01111111111111111111111111111111
         num:   -2147483648
                10000000000000000000000000000000
         num+1: -2147483647
                10000000000000000000000000000001
      

      【讨论】:

      • 我很困惑。在您的标题中,您明确表示您有许多 1 + 31 (= 32) 个字符。而且您知道标志使用了 1 位。是什么让你认为你仍然可以创建一个 32 位的整数?
      • 编辑:愚蠢仓促的评论。
      • @JeroenVannevel:我澄清了我的回答。
      • 您链接到的那个网页非常具有误导性。正如它声称的那样,最高位绝对不是为加号或减号保留的。
      • MSB 是一个值位,表示 -2^31。如果您误导性地将其称为“符号位”,则您错误地暗示它没有自己的值。请不要再称它为“符号位”了。
      【解决方案4】:

      使用 Integer.parseInt 时,必须明确确定转换值的符号。所以如果它的 Integer.MIN_VALUE,对于 parseInt 它看起来像这样:

      Integer.parseInt("-10000000000000000000000000000000", 2);
      

      — 仍然是 32 位,但以减号作为前缀。如果不使用符号,则第一位(“符号位”)默认为零(正值),您将无法转换包含超过 31 位的值,这就是 NumberFormatException — Integer.MAX_VALUE 为 01111111111111111111111111111111 的原因

      或者你可以使用 Integer.parseUnsignedInt :

      Integer.parseUnsignedInt("10000000000000000000000000000000", 2);
      

      这里二进制值将“按原样”转换,第一位将被解释为符号位。两种情况的结果都是-2^31

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-29
        • 2017-01-11
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多