5

给定字符串“0”中的二进制数,我将其转换为long以找到它的按位非/补码。

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

哪个打印

11111111111111111111111111111111111111111111111111111111111111

即,64 个 1。但我找不到这个的补充。

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

我得到 java.lang.NumberFormatException。我是什么做的?

4

3 回答 3

7

当你反转零

number = ~number

你得到负面的。该Long.parseLong(String, int)方法期望用减号前缀表示负数。当您将 64 1-s 传递给该方法时,它认为这是一个溢出,并返回一个错误。

解决此问题的一种方法是在解析值之前检查长度是否小于 64。如果长度正好是 64,则砍掉第一个数字,然后解析其余的数字。然后检查初始数字。如果为零,则保留解析后的数字;否则,使用二进制OR设置最高有效位:

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);
    }
}
于 2013-08-11T15:56:16.447 回答
5

0 的补码是 64 个 1,相当于 -1,因为 Java 使用二进制补码

Long.parseLong(String, int) 

需要一个有符号的 long (如果数字是负数,它需要一个前导-),但是你传递给它 64 个 1,它们应该代表 -1,但不要以这种形式。

鉴于对于负数,它期望一个负号,传递它 64 1 会导致它相信这个数字太大。

编辑(dasblinkenlight 的修复说明:无法在评论中正确格式化):
所以如果String s =

"1111111111111111111111111111111111111111111111111111111111111111";

,我们有:

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

的二进制形式res是:

0111111111111111111111111111111111111111111111111111111111111111

现在,如果我们知道第一个chars'1'那么我们执行以下操作:

 res |= (1L << 63);

(1L << 63)产生:

1000000000000000000000000000000000000000000000000000000000000000

因此,按位或赋值res产生 64 个 1,在二进制补码中为 -1,如所愿。

于 2013-08-11T15:57:24.370 回答
0

这是因为 Long.parseLong(以及 Integer.parseInt 等)无法解析二进制补码,因此“111111111111111111111111111111111111111111111111111111111111111”是一个超过 Long.MAX_VALUE 的正数。但是我们可以使用 BigInteger

long l = new BigInteger("1111111111111111111111111111111111111111111111111111111111111111", 2).longValue()

这会产生预期结果 = -1

于 2013-08-29T11:19:32.987 回答