使用 Integer.parseInt 转换 32 位二进制字符串失败

Posted

技术标签:

【中文标题】使用 Integer.parseInt 转换 32 位二进制字符串失败【英文标题】:Converting 32-bit binary string with Integer.parseInt fails 【发布时间】:2012-02-11 22:07:12 【问题描述】:

为什么这部分代码会失败:

Integer.parseInt("11000000000000000000000000000000",2);

Exception in thread "main" java.lang.NumberFormatException: For input string: "11000000000000000000000000000000"

据我了解,整数是 32 位值。上面代码中的 0 和 1 的数量是 32。如果有 31,则代码有效。为什么会这样?

【问题讨论】:

这里接受的答案不正确。可以在此处找到具有正确答案的相同问题:Java, Long.parse binary String 【参考方案1】:

您的代码失败,因为它试图解析一个需要 33 位才能存储为有符号整数的数字。

带符号的int 是二进制补码表示的 32 位值,其中第一位表示数字的符号,其余 31 位表示数字的值。 (-ish。)Java 只支持有符号整数,parseInt() 和朋友不应该解析二进制补码位模式——因此解释右边第 32 位的1 或(可能暗示)0作为标志。它们旨在支持解析人类可读的表示,这是符号的可选-(或+),后跟数字的绝对值。

在这种情况下,这是一种错误的直觉,会导致您期望您所描述的行为:如果您解析 any 除了基数 2 之外的其他基数(或者可能是其他常用的二次幂)基数),您是否希望输入的第一个数字影响符号?显然你不会;比如说,parseInt("2147483648") return -2147483648 按设计 将是 php 级别的疯狂。

特殊外壳的二次幂基地也感觉很奇怪。最好有一种单独的方法来处理位模式,例如this answer 中的方法。

【讨论】:

我只是再次重新阅读了 Integer.parseInt() 的 javadocs,我没有看到任何说“这不解析负数”(事实上,它说“有符号整数”),或者,至少明确地说,“这不会解析位模式”。事实上,正如 javadocs 中所描述的,有人可能会争辩说 55 个 0 的字符串应该解析为 0。我认为这种行为是一个错误。但看起来 Oracle 或 OpenJDK 不会修复它。您在 javadocs 中看到与此相矛盾的内容吗? @user949300 parseInt 将解析负二进制数,如果您将它们作为“-10010110”传递。它还将解析一个由 55 个零组成的字符串,因为它是 int 的有效值。没有前导零的 32 位数字不是有效的 int 值,因此被拒绝。 @user949300 我所说的“不会解析位模式”的意思是,“Integer.parseInt(str, 2)”解析的是一个以 2 为底的数字。它不会解析字符串化32 位整数的二进制补码二进制表示。我不认为这是一个错误,我只是认为它是该方法不适用的东西 - 它正在解析任意基数中数字的“人类”文本表示。 @Interdial 嗯,我认为 55 个零不起作用。感谢测试!我认为 55 个 0 有效而 32 个 1 无效,这很奇怪,但事实就是这样。 Java 表示 2 的补码 中的整数,而不是符号大小。【参考方案2】:

根据docs,Integer 的最大值为2^31-1。其中,二进制是:

1111111111111111111111111111111

换句话说,连续 31 个1

【讨论】:

【参考方案3】:

这是因为对于 Integer.parseInt "11000000000000000000000000000000" 不是 -1073741824 的二进制补码表示,而是一个正值 3221225472,它不适合 int 值范围 -2147483648 到 2147483647。但是我们可以解析二进制补码字符串大整数:

int i = new BigInteger("11000000000000000000000000000000", 2).intValue()

这给出了预期的 -1073741824 结果

【讨论】:

【参考方案4】:

即使您的字符串“11 .....lots of zeros”是负整数的合法二进制表示,Integer.parseInt() 也会失败。我认为这是一个错误。

添加一点轻浮,因为重读这篇文章听起来太迂腐了,我知道甲骨文可能并不在乎我是否认为这是一个错误。 :-)

你可以试试:

   long avoidOverflows = Long.parseLong("11000000000000000000000000000000",2);
   int thisShouldBeANegativeNumber = (int)avoidOverflows);
   System.out.println(avoidOverflows + " -> " + thisShouldBeANegativeNumber);

你应该看到 3221225472 -> -1073741824

您有时必须对颜色执行此操作,具体取决于颜色作为文本的存储方式。

顺便说一句,如果您正在解析十六进制表示并且您正在解析像“88888888”这样的负数,则可能会发生确切的事情。您需要使用 Long.parseLong() 然后进行转换。

【讨论】:

这不是错误。 JavaDoc 指出,如果您想要来自parseInt() 的负整数,则必须在字符串的开头有一个ASCII 减去-。看看这个问题:Java, Long.parse binary String

以上是关于使用 Integer.parseInt 转换 32 位二进制字符串失败的主要内容,如果未能解决你的问题,请参考以下文章

Integer.parseInt 是在 Java 中将 String 转换为 Int 的最佳方法?

Java将字符串强制转换为整形数据的方法——Integer.parseInt

integer类的parseint方法(基本数据类型包装类 )

Android App 在第 54 行(Integer.parseInt)崩溃,不完全确定原因

java中的语句integer.parseint()是啥意思

vb中integer是啥意思啊