Long.parseLong throws NumberFormatException for binary string

435 views Asked by At

we have byte string s = "1111000000000111000000000001000000000010010000000000000000000000"(this value equal -1150951111012646912), if we use Long.parseLong(s, 2), we got "

java.lang.NumberFormatException: For input string: "1100000001000000010000000100000000001110000000010000010000000000" under radix 2".

i fixed this problem with this way to convert

 new BigInteger(s, 2).longValue();

Explain please i can't understand what happend?

Same situation with this value: s = 1100000001000000010000000100000000001110000000010000010000000000 (equal -4593600976060873728)

new BigInteger(s, 2).longValue();
3

There are 3 answers

0
0x150 On

You're passing in a size 64 binary string, which is bigger than the signed byte size of a long. Since parseLong doesn't accept unsigned binary representations and instead wants a - or (an optional) + in front of the number to denote the sign, it throws an error. The max byte length you can pass into parseLong is 63.

An equivalent parseLong call to your first example would be Long.parseLong("-111111111000111111111110111111111101110000000000000000000000", 2), using the - sign and the two's complement of the number.

0
Mr. Polywhirl On

You are trying to parse a 64-bit unsigned (long) integer as a 64-bit signed (long) integer.

Java's long is not unsigned. You will only be able to store a positive number up to 63 bits. The max value for a long is 9,223,372,036,854,775,807 or 2^(63).

The most-significant bit (left-most) is the signed bit.

  • If it's a 64-bit string that begins with a 1, it's negative.
  • If it's less than 64 bits, it's positive and the leading 0 will not be displayed.

Note: Any leading zeroes will not be displayed.

import java.math.BigInteger;

public class NumberUtils {

  static final String MIN_SIGNED_LONG_BINARY = Long.toBinaryString(Long.MIN_VALUE);
  static final String MAX_SIGNED_LONG_BINARY =
      padStart(Long.toBinaryString(Long.MAX_VALUE), 64, "0");

  public static void main(String[] args) {
    parseBinary("1111000000000111000000000001000000000010010000000000000000000000");
    parseBinary("1100000001000000010000000100000000001110000000010000010000000000");
  }

  private static void parseBinary(String str) {
    BigInteger bigInt = new BigInteger(str, 2);
    System.out.println(bigInt.longValue());
    try {
      Long.parseLong(str, 2);
    } catch (NumberFormatException e) {
      System.out.printf(
          "Error:%n* Min: %s (%d bits)%n* Val: %s (%d bits)%n* Max: %s (%d bits)%n",
          MIN_SIGNED_LONG_BINARY,
          MIN_SIGNED_LONG_BINARY.length(),
          str,
          str.length(),
          MAX_SIGNED_LONG_BINARY,
          MAX_SIGNED_LONG_BINARY.length());
    }
  }

  public static String padStart(String inputString, int targetLength, String padString) {
    if (inputString.length() >= targetLength) return inputString;
    StringBuilder sb = new StringBuilder();
    while (sb.length() < targetLength - inputString.length()) {
      sb.append(padString);
    }
    return sb.append(inputString).toString();
  }
}

Output

-1150951111012646912
Error:
* Min: 1000000000000000000000000000000000000000000000000000000000000000 (64 bits)
* Val: 1111000000000111000000000001000000000010010000000000000000000000 (64 bits)
* Max: 0111111111111111111111111111111111111111111111111111111111111111 (64 bits)
-4593600976060873728
Error:
* Min: 1000000000000000000000000000000000000000000000000000000000000000 (64 bits)
* Val: 1100000001000000010000000100000000001110000000010000010000000000 (64 bits)
* Max: 0111111111111111111111111111111111111111111111111111111111111111 (64 bits)
0
WJS On

The short answer is that neither Integer.parseInt nor Long.parseLong can parse twos complement negative numbers without replacing the sign bit with an explicit '+' or '-' sign.

This is probably in keeping with parsing a decimal number such as the following:

String max = "9223372036854775807";  // Long.MAX_VALUE         
String maxPlus1 = "9223372036854775808"; // Long.MAX_VALUE+1 
long m = Long.parseLong(max,10); //OK
long m1 =Long.parseLong(maxPlus1,10)); // throws exception

To parse your two's complement value of long or any other value you can use Long.parseUnsignedLong. All the following three method calls correctly parse the values, printing out Long.MIN_VALUE, the fourth one being your specific value in your question.

System.out.println(Long.parseUnsignedLong("1000000000000000000000000000000000000000000000000000000000000000",2));
System.out.println(Long.parseUnsignedLong("8000000000000000",16));
System.out.println(Long.parseUnsignedLong("9223372036854775808",10));
System.out.println(Long.parseUnsignedLong("1111000000000111000000000001000000000010010000000000000000000000",2));

prints

-9223372036854775808
-9223372036854775808
-9223372036854775808
-1150951111012646912