简体   繁体   English

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

[英]Java Integer.parseInt() for 32-bit signed binary string throws NumberFormatException

Is this Java Api's bug?这是 Java Api 的错误吗?

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

I expect it to be true without any question.我希望它毫无疑问地是真的。 But it throws below exception:但它抛出以下异常:

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)

So if I have a binary String , eg 11010011100101010001100010010010, How can I get its decimal number(-745203566) in Java?因此,如果我有一个二进制字符串,例如 11010011100101010001100010010010,我如何在 Java 中获得它的十进制数(-745203566)? DIY? DIY? Write code to implement below equation?编写代码来实现下面的等式?

在此处输入图片说明

Integer.valueOf(String, int radix) and Integer.parseInt(String, int radix) will only parse numbers of value -2 147 483 648 to 2 147 483 647, ie the values of 32-bit signed integers. Integer.valueOf(String, int radix)Integer.parseInt(String, int radix)只会解析值 -2 147 483 648 到 2 147 483 647 的数字,即 32 位有符号整数的值。

These functions cannot interpret two's complement numbers for binary ( radix = 2 ), because the string being passed can be of any length, and so a leading 1 could be part of the number or the sign bit.这些函数无法解释二进制 ( radix = 2 ) 的二进制补码,因为传递的字符串可以是任意长度,因此前导 1 可能是数字或符号位的一部分。 I guess Java's developers decided that the most logical way to proceed is to never accept two's complement, rather than assume that a 32nd bit is a sign bit.我猜 Java 的开发人员认为最合乎逻辑的方法是永远不要接受二进制补码,而不是假设第 32 位是符​​号位。

They read your input binary string as unsigned 3 549 763 730 (bigger than max int value).他们将您的输入二进制字符串读取为无符号 3 549 763 730(大于最大 int 值)。 To read a negative value, you'd want to give a positive binary number with a - sign in front.要读取负值,您需要给出一个前面带有-符号的正二进制数。 For example for -5 :例如-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

Solutions:解决方案:

I suggest, first, that if you can store it as a positive number with extra sign information on your own (eg a - symbol), do that.我建议,首先,如果您可以将其存储为带有您自己的额外符号信息的正数(例如-符号),请执行此操作。 For example:例如:

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

If you need to use signed binary strings, in order to take a negative number in binary two's complement form (as a string) and parse it to an int, I suggest you take the two's complement manually, convert that into int, and then correct the sign.如果需要使用带符号的二进制字符串,为了取二进制补码形式的负数(作为字符串)并解析为int,建议您手动取二进制补码,将其转换为int,然后更正标志。 Recall that two's complement = one's complement + 1, and one's complement is just reverse each bit.回想一下,二的补码 = 一的补码 + 1,而一的补码只是反转每一位。

As an example implementation:作为示例实现:

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

You could also write your own version of Integer.parseInt for 32-bit two's complement binary numbers.您还可以为 32 位二进制补码编写自己的Integer.parseInt版本。 This, of course, assumes you're not using Java 8 and can't just use Integer.parseUnsignedInt , which @llogiq pointed out while I was typing this.当然,这假设您没有使用 Java 8 并且不能只使用Integer.parseUnsignedInt ,@llogiq 在我输入时指出了这一点。

EDIT: You could also use Long.parseLong(String, 2) first, then calculate the two's complement (and mask it by 0xFFFFFFFF), then downgrade the long down to int .编辑:您也可以先使用Long.parseLong(String, 2) ,然后计算二进制补码(并用 0xFFFFFFFF 将其屏蔽),然后将long降级为int Faster to write, probably faster code.写得更快,可能更快的代码。

The API docs for Integer.toBinaryString(..) explicitly state: Integer.toBinaryString(..)的 API 文档明确指出:

The value of the argument can be recovered from the returned string s by calling Integer.parseUnsignedInt(s, 8) .可以通过调用Integer.parseUnsignedInt(s, 8)从返回的字符串 s 中恢复参数的值。

(as of Java 8u25) I think this is a documentation error, and it should read Integer.parseUnsignedInt(s, 2) . (从 Java 8u25 开始)我认为这是一个文档错误,它应该读取Integer.parseUnsignedInt(s, 2) Note the Unsigned .注意Unsigned This is because the toBinaryString output will include the sign bit.这是因为toBinaryString输出将包含符号位。

Edit: Note that even though this looks like it would produce an unsigned value, it isn't.编辑:请注意,即使这看起来会产生无符号值,但事实并非如此。 This is because Java does not really have a notion of unsigned values, only a few static methods to work with ints as if they were unsigned.这是因为Java并没有真正具有无符号值的概念,只有几个静态方法与整数工作,好像他们无符号。

I was struggling with a similar issue and the above answer from Ilogic worked great for me. 我正在努力解决类似的问题,Ilogic的上述回答对我来说非常有效。 thanks. 谢谢。 :). :)。 If I could upvote instead of posting here, I would have. 如果我能投票赞成而不是在这里发表,我会的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Integer.parseInt转换32位二进制字符串失败 - Converting 32-bit binary string with Integer.parseInt fails 为什么代表数字的String的Integer.parseInt在J2ME中抛出java.lang.NumberFormatException? - Why Integer.parseInt of a String representing a number throws java.lang.NumberFormatException in J2ME? 使用Integer.parseInt(String arg)时出现Java NumberFormatException - Java NumberFormatException when using Integer.parseInt(String arg) 使用 Integer.parseInt 时的 Java NumberFormatException - Java NumberFormatException when using Integer.parseInt Java仅从文本文件中获取数字:Integer.ParseInt throws NumberFormatexception - Java grabbing numbers only from Text File: Integer.ParseInt throws NumberFormatexception Integer.parseInt()使用UTF-8文件抛出NumberFormatException - Integer.parseInt() throws NumberFormatException with UTF-8 files Integer.parseInt引发的NumberFormatException - NumberFormatException thrown by Integer.parseInt Integer.parseInt 和 NumberFormatException 上 Android - Integer.parseInt and NumberFormatException on Android 为什么我得到一个 Integer.parseInt(String) 一个 numberformatexception? - Why do i get for an Integer.parseInt(String) an numberformatexception? java.lang.NumberFormatException:Integer.Parseint()为null - java.lang.NumberFormatException: null with Integer.Parseint()
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM