Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to parse 64 bit binary numbers to long

Given binary number in a string "0", I converted it to long to find its Bitwise Not/Complement.

long number = Long.parseLong("0",2);
number = ~number;
System.out.println(Long.toBinaryString(number));

which prints

1111111111111111111111111111111111111111111111111111111111111111

i.e., 64 1's. But I'm unable to find complement of this.

Long.parseLong("111111111111111111111111111111111111111111111111111111111111111",2); //fails

I get java.lang.NumberFormatException. What am I to do?

like image 509
Frozen Crayon Avatar asked Aug 11 '13 15:08

Frozen Crayon


2 Answers

When you invert zero

number = ~number

you get negative one. The Long.parseLong(String, int) method expects negative numbers to be represented with a minus prefix. When you pass 64 1-s to the method, it thinks it's an overflow, and returns an error.

One way to fix this is to check that the length is less than 64 before you parse the value. If the length is exactly 64, chop off the first digit, and parse the rest of the number. Then check the initial digit. If it is zero, leave the parsed number as is; otherwise, use binary OR to set the most significant bit:

String s = "1111111111111111111111111111111111111111111111111111111111111111";
long res;
if (s.length() < 64) {
    res = Long.parseLong(s, 2);
} else {
    res = Long.parseLong(s.substring(1), 2);
    if (s.charAt(0) == '1') {
        res |= (1L << 63);
    }
}
like image 75
Sergey Kalinichenko Avatar answered Nov 04 '22 18:11

Sergey Kalinichenko


The complement of 0 is 64 1's, which is equivalent to -1, since Java uses two's complement.

Long.parseLong(String, int) 

expects a signed long (aka if the number is negative, it expects a leading -), but you are passing it 64 1's, which are supposed to represent -1, but do not in this form.

Given that for negatives, it expects the a negative sign, passing it 64 1's causes the it to believe that the number is too large.

EDIT (explanation of dasblinkenlight's fix: couldn't properly format in comment):
So if String s =

"1111111111111111111111111111111111111111111111111111111111111111";

, and we have:

long res = Long.parseLong(s.substring(1), 2);

The binary form of res is:

0111111111111111111111111111111111111111111111111111111111111111

Now, if we know that the first char of s is '1', then we do the following:

 res |= (1L << 63);

(1L << 63) produces:

1000000000000000000000000000000000000000000000000000000000000000

So, the bitwise-or assignment to res yields 64 1's, which in two's complement is -1, as desired.

like image 5
Steve P. Avatar answered Nov 04 '22 18:11

Steve P.