Преобразование 32-битной двоичной строки с Integer.parseInt не выполняется
Почему эта часть кода не работает:
Integer.parseInt("11000000000000000000000000000000",2);
Exception in thread "main" java.lang.NumberFormatException: For input string: "11000000000000000000000000000000"
Насколько я понимаю, Integer - это 32-битное значение. Число нулей и единиц в верхнем коде равно 32. Если есть код, он работает. Почему это так?
Ответы
Ответ 1
Ваш код выходит из строя, потому что он пытается проанализировать число, которое потребует 33 бита для хранения в виде целого числа со знаком.
Подписанный int
представляет собой 32-битное значение в двух дополнительных представлениях, где первый бит будет указывать знак числа, а остальные 31 бит - значение числа. (-ish.) Java поддерживает только целые числа со знаком, а parseInt()
и друзья не должны анализировать два битовых шаблона дополнения и, таким образом, интерпретировать 1
или (возможно подразумеваемый) 0
в 32-й позиции справа как знак. Они предназначены для поддержки разбора удобочитаемого перепечатки, который является необязательным -
(или +
) для знака, за которым следует абсолютное значение числа.
В этом контексте это ложная интуиция, которая заставляет вас ожидать описанного вами поведения: если вы анализировали любую другую базу, кроме базы 2 (или, возможно, другую часто используемую силу два базы), вы ожидали, что первая цифра ввода повлияет на знак? Очевидно, вы бы этого не сделали; имея, скажем, parseInt("2147483648")
return -2147483648
по дизайну, будут уровни безумия.
Специальная оболочка из двух баз также кажется странной. Лучше иметь отдельный подход к обработке битовых шаблонов, например, в этом ответе.
Ответ 2
В соответствии с docs максимальное значение Integer 2^31-1
. Что в двоичном формате:
1111111111111111111111111111111
Иными словами, 31 1
в строке.
Ответ 3
Это связано с тем, что для Integer.parseInt "1100000000000000000000000000000000" не является двухкомпонентным представлением -1073741824, а положительным значением 3221225472, которое не соответствует диапазону значений int от -2147483648 до 2147483647. Но мы можем проанализировать два бинарных представления двоичного кода с помощью BigInteger:
int i = new BigInteger("11000000000000000000000000000000", 2).intValue()
это дает ожидаемый результат -1073741824
Ответ 4
Даже если ваша строка "11..... много нулей" является юридическим двоичным представлением отрицательного целого числа, Integer.parseInt() терпит неудачу на нем. Я считаю это ошибкой.
Добавление немного легкомыслия, так как при перечитывании этого сообщения это звучит слишком педантично, я понимаю, что Oracle, вероятно, не заботится о том, думаю, что это ошибка или нет.: -)
Вы можете попробовать:
long avoidOverflows = Long.parseLong("11000000000000000000000000000000",2);
int thisShouldBeANegativeNumber = (int)avoidOverflows);
System.out.println(avoidOverflows + " -> " + thisShouldBeANegativeNumber);
вы должны увидеть 3221225472 → -1073741824
Вам иногда приходится делать это с помощью цветов в зависимости от того, как они хранятся в виде текста.
Кстати, точная вещь может произойти, если вы разбираете шестнадцатеричное представление, и вы анализируете отрицательное число, например "88888888". Вам нужно использовать Long.parseLong(), а затем конвертировать.