Why is 1 plus 31 zeros not a valid integer, if bit flags are 31 length, plus one negative/positive flag?

拥有回忆 提交于 2019-12-13 08:09:55

问题


According to this, in the around-fourth paragraph below the first table, says

In general, we will use an integer to represent a set on a domain of up to 32 values (or 64, using a 64-bit integer), with a 1 bit representing a member that is present and a 0 bit one that is absent.

If that's true, then why does this 32 digit binary number exceed Integer.MAX_VALUE?

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

Error:

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)

回答1:


In base 2, 10000000000000000000000000000000 (that's 31 zeroes) is 2^31. A Java int is a 32-bit twos complement representation of numbers between -2^31 and 2^31-1; and this range of course does not include 2^31. That's why this value can't be converted to an int - although a long would be fine.

If you have a Java int whose bits are 10000000000000000000000000000000 (still 31 zeroes), that's -2^31.

It's not true that the first bit of a Java int is a positive/negative flag. It's simply a digit with place value of -2^31.




回答2:


It exceeds Integer.MAX_VALUE because it really does exceed Integer.MAX_VALUE. It's Integer.MAX_VALUE + 1, which you can absolutely calculate in int-space and you can write it down as 0x80000000 or as Integer.MIN_VALUE, but it'll be negative.

Which is why parseInt complains.

You just can't parse it that way - you can absolutely represent a bitvector with the 32nd bit set with an int. The "sign bit" (which is a misleading name, but we seem to be stuck with it) is just a normal bit like any other bit. Its special meaning only comes into play for:

  • converting to/from String
  • converting to a wider or floating point type
  • division and remainder
  • right shift, see >> vs >>>
  • comparisons except equality, for example 1 > 0x80000000. You can compare long x and y as if they were unsigned with (x ^ Long.MIN_VALUE) < (y ^ Long.MIN_VALUE) (for int you can cast to long and mask with 0xffffffffL of course)

The "sign bit" is just an other bit without special meaning for:

  • addition and subtraction
  • bitwise operations (including left shift)
  • multiplication
  • equality testing
  • converting to a narrower type

If you're interpreting your int as a bitvector, the "sign bit" will just be a normal bit, but you must take care that all the operations you do on it agree on that.




回答3:


Original answer:


I figured it out. This webpage cleared it up for me:

Java integers are 32 bits. The highest bit is reserved for plus or minus sign. So you can set/unset 31 one-bit flags

My misunderstanding was that bit flags used the 32nd bit in an integer in this way, as the negative or positive marker, as if it were an option to do so. But Java defines an integer that way, so it's not an option--it's a result or by-product of that definition. An integer has only 31 bits that represent the number itself. The 32nd serves as the plus-minus.

(After writing this, I can see that it makes no sense to even say "bit flags use" anything. Bit flags are concept, the integer is a concrete type.)


Update: Some observations:

Integer.MIN_VALUE equals -2147483648, which in binary, is

10000000000000000000000000000000

The first bit indicates negative. It's a sign bit in this situation because this is a signed integer (Integer.MIN_VALUE is negative, and min-and-max are equidistant to zero). Were it an unsigned integer, it would just be another value-bit.

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

Signed:

int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -231 and a maximum value of 231-1.

Unsigned:

In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 232-1. Use the Integer class to use int data type as an unsigned integer. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.

Again: Integer.MIN_VALUE equals -2147483648, which in binary, is

10000000000000000000000000000000

Changing that "sign bit" to a zero does not make this 2147483648 (Integer.MAX_VALUE). It makes it

00000000000000000000000000000000

which is zero. Integer.MAX_VALUE in binary is

01111111111111111111111111111111

Switching the "sign bit" to a one doesn't make it MIN_VALUE.

11111111111111111111111111111111

Attempting to parse this fails, because 32 bits are too large for the value portion of a signed integer:

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

Error:

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)

Rather

11111111111111111111111111111111

is

 1111111111111111111111111111111

with a "sign bit" indicating negative. A binary digit with thirty-two ones is -1. I can't get my mind around why at the moment. I also don't know how to parse a negative (signed) binary. This

Integer.parseInt("-1111111111111111111111111111111", 2)

is equal to

   num:   -2147483647
          10000000000000000000000000000001

So it's overflowing or something...

Testing class:

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');
  }
}

Output:

-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



回答4:


When you use Integer.parseInt, you must explicitly determine the sign of the converting value. So if its Integer.MIN_VALUE, for parseInt it looks like this:

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

— still 32 bits, but with minus as prefix. If no sign is used, the first bit ("sign bit") will be zero (positive value) by default and you will not be able to convert value that consists of more than 31 bits that's why you NumberFormatException — Integer.MAX_VALUE is 01111111111111111111111111111111

Or you may use Integer.parseUnsignedInt :

Integer.parseUnsignedInt("10000000000000000000000000000000", 2);

Here the binary value will be converted "as is" and the first bit will be interpreted as a sign bit. The result in both cases is -2^31



来源:https://stackoverflow.com/questions/23259194/why-is-1-plus-31-zeros-not-a-valid-integer-if-bit-flags-are-31-length-plus-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!