32 位有符号二进制字符串的 Java Integer.parseInt() 抛出 NumberFormatException

2024-01-04

这是Java Api的bug吗?

    int i = 0xD3951892;
    System.out.println(i); // -745203566
    String binString = Integer.toBinaryString(i);
    int radix = 2;
    int j = Integer.valueOf(binString, radix );
    Assertions.assertThat(j).isEqualTo(i);

我希望毫无疑问这是真的。但它抛出以下异常:

java.lang.NumberFormatException: For input string: "11010011100101010001100010010010"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:495)
at java.lang.Integer.valueOf(Integer.java:556)
at com.zhugw.temp.IntegerTest.test_valueof_binary_string(IntegerTest.java:14)

所以如果我有一个二进制 String ,例如11010011100101010001100010010010,Java中如何获取其十进制数(-745203566)? DIY?编写代码来实现下面的等式?


Integer.valueOf(String, int radix) and Integer.parseInt(String, int radix)只会解析值 -2 147 483 648 到 2 147 483 647 的数字,即 32 位有符号整数的值。

这些函数无法将二进制补码解释为二进制 (radix = 2),因为传递的字符串可以是任意长度,因此前导 1 可以是数字或符号位的一部分。我猜 Java 开发人员认为最合乎逻辑的处理方式是永远不接受二进制补码,而不是假设第 32 位是符​​号位。

他们将您的输入二进制字符串读取为无符号 3 549 763 730(大于最大 int 值)。要读取负值,您需要给出一个正二进制数-在前面签名。例如对于-5:

Integer.parseInt("1011", 2); // 11
    // Even if you extended the 1s to try and make two's complement of 5,
    // it would always read it as a positive binary value
Integer.parseInt("-101", 2); // -5, this is right

解决方案:

我建议,首先,如果您可以将其存储为正数,并自行添加额外的符号信息(例如-符号),这样做。例如:

String binString;
if(i < 0)
    binString = "-" + Integer.toBinaryString(-i);
else // positive i
    binString = Integer.toBinaryString(i);

如果您需要使用有符号的二进制字符串,为了以二进制补码形式(作为字符串)获取负数并将其解析为 int,我建议您手动获取补码,将其转换为 int,然后更正标志。回想一下,二进制补码 = 二进制补码 + 1,而二进制补码只是将每一位取反。

作为示例实现:

String binString = "11010011100101010001100010010010";
StringBuilder onesComplementBuilder = new StringBuilder();
for(char bit : binString.toCharArray()) {
    // if bit is '0', append a 1. if bit is '1', append a 0.
    onesComplementBuilder.append((bit == '0') ? 1 : 0);
}
String onesComplement = onesComplementBuilder.toString();
System.out.println(onesComplement); // should be the NOT of binString
int converted = Integer.valueOf(onesComplement, 2);
// two's complement = one's complement + 1. This is the positive value
// of our original binary string, so make it negative again.
int value = -(converted + 1);

您也可以编写自己的版本Integer.parseInt对于 32 位二进制补码。当然,这是假设您没有使用 Java 8 并且不能只使用Integer.parseUnsignedInt,@llogiq 在我打字时指出的。

编辑:你也可以使用Long.parseLong(String, 2)首先,然后计算二进制补码(并用 0xFFFFFFFF 屏蔽它),然后降级long向下int。写得更快,代码可能也更快。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

32 位有符号二进制字符串的 Java Integer.parseInt() 抛出 NumberFormatException 的相关文章

随机推荐