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

发布于 2024-12-27 14:45:43 字数 289 浏览 2 评论 0原文

为什么这部分代码失败:

Integer.parseInt("11000000000000000000000000000000",2);

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

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

Why does this part of code fail:

Integer.parseInt("11000000000000000000000000000000",2);

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

As far as I understand Integer is a 32 bit value. The number of zeros and ones in the upper code is 32. If there are 31 the code works. Why is that so?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

万水千山粽是情ミ 2025-01-03 14:45:43

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

有符号 int 是采用二进制补码表示形式的 32 位值,其中第一位表示数字的符号,其余 31 位表示数字的值。 (-ish。)Java 仅支持有符号整数,并且 parseInt() 和朋友不应该解析二进制补码位模式 - 从而解释 1 或(可能隐含的)0 位于右侧第 32 个位置作为符号。它们旨在支持解析人类可读的表示,即符号的可选 - (或 +),后跟数字的绝对值。

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

特殊外壳的两个底座也感觉很奇怪。最好采用一种单独的方法来处理位模式,例如此答案中的方法。

Your code fails because it tries to parse a number that would require 33 bits to store as a signed integer.

A signed int is a 32 bit value in two's complement representation, where the first bit will indicate the sign of the number, and the remaining 31 bits the value of the number. (-ish.) Java only supports signed integers, and parseInt() and friends aren't supposed to parse two's complement bit patterns – and thus interpret the 1 or (possibly implied) 0 at the 32nd position from the right as the sign. They're meant to support parsing a human-readable reprentation, which is an optional - (or +) for the sign, followed by the absolute value of a number.

In this context, it's a false intuition that leads you to expect the behaviour you describe: if you were parsing any other base besides base 2 (or maybe the other commonly used power-of-two bases), would you expect the first digit of the input to affect the sign? Obviously you wouldn't; having, say, parseInt("2147483648") return -2147483648 by design would be PHP levels of crazy.

Special-casing power-of-two bases also feels odd. Better to have a separate approach to handling bit patterns, for example the one in this answer.

吾性傲以野 2025-01-03 14:45:43

根据文档,最大整数的值为2^31-1。其中,二进制为:

1111111111111111111111111111111

换句话说,31 个 1 连续。

According to the docs, the max value of an Integer is 2^31-1. Which, in binary is:

1111111111111111111111111111111

In other words, 31 1's in a row.

入画浅相思 2025-01-03 14:45:43

这是因为对于 Integer.parseInt 来说,“11000000000000000000000000000000”不是 -1073741824 的二进制补码表示,而是一个正值 3221225472,它不适合 int 值范围 -2147483648 到 2147483647。但是我们可以使用 BigInteger 解析补码二进制字符串表示形式:

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

这给出了预期的 -1073741824 结果

This is because for Integer.parseInt "11000000000000000000000000000000" is not a two's complement representation of -1073741824 but a positive value 3221225472 which does not fit into int values range -2147483648 to 2147483647. But we can parse two's complement binary string representation with BigInteger:

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

this gives expected -1073741824 result

半城柳色半声笛 2025-01-03 14:45:43

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

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

你可以尝试:

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

你应该看到
3221225472-> -1073741824

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

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

Even though your string, "11.....lots of zeros" is a legal binary representation of a negative integer, Integer.parseInt() fails on it. I consider this a bug.

Adding a little levity, since on rereading this post it sounds too pedantic, I understand that Oracle probably doesn't care much whether I think this is a bug or not. :-)

You can try:

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

you should see
3221225472 -> -1073741824

You sometimes have to do this with Colors depending on how they are stored as text.

BTW, exact thing can happen if you are parsing a Hex representation and you are parsing a negative number like "88888888". You need to use Long.parseLong() then convert.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文