Значение i для (i == -i && i! = 0) для возврата true в Java

101

У меня следующее ifсостояние.

if (i == -i && i != 0)

Какое значение iвернет trueдля этого условия в Java?

Я не могу придумать какой-либо такой ценности для iрассмотрения двух дополнений в Java.

Я также хотел бы получить алгебраическое доказательство того, какой ответ это условие имеет (в контексте Java)?

Солнечно
источник
2
как насчет if (i! = null)
zxc
4
Обратите внимание, что -0.0это также== 0
Питер Лоури
2
напишите это какif(i && i == -i)
Grijesh Chauhan
10
@GrijeshChauhan В Java? Ты уверен ?
Denys Séguret
3
@harold Я много раз спрашивал в интервью за последние четыре года, и мало кто действительно понимает это даже с намеками.
Питер Лоури

Ответы:

126

Единственное intзначение, для которого это работает Integer.MIN_VALUE.

Это потому, что целые числа инвертируются с использованием способа дополнения до двух .

С помощью

System.out.println(Integer.toBinaryString(Integer.MIN_VALUE));

вы видите, что Integer.MIN_VALUEэто

10000000000000000000000000000000

Принятие отрицательного значения выполняется сначала заменой местами 0и 1, что дает

01111111111111111111111111111111

и добавив 1, что дает

10000000000000000000000000000000

Как вы можете видеть в приведенной мной ссылке, Википедия упоминает проблему с наиболее отрицательными числами и указывает ее единственное исключение:

Самое отрицательное число в дополнении до двух иногда называют «странным числом», потому что это единственное исключение.

Конечно, у вас будет то же самое явление, Long.Min_Valueесли вы сохраните его в longпеременной.

Обратите внимание, что это связано только с выбором, который был сделан в отношении двоичного хранения int в Java . Другое (плохое) решение могло, например, заключаться в том, чтобы отменить, просто изменив наиболее значимый бит и оставив другие биты неизменными, это позволило бы избежать этой проблемы с MIN_VALUE, но сделало бы 2 разных 0значения и сложную двоичную арифметику (как бы вы увеличено например?).

Дени Сегюре
источник
2
Стоит отметить, что ранние бинарные компьютеры действительно использовали реализацию знака и величины для целых чисел, описанных в вашем последнем абзаце; как и числа с плавающей запятой IEE754. en.wikipedia.org/wiki/…
Dan Is Fiddling By Firelight
1
Re: «это относится только к выбору, который был сделан в отношении двоичного хранилища int»: и к выбору того, как обрабатывать переполнение. Правило, которое использует Java, не совпадает с правилом, используемым (скажем) C, или правилом, используемым (скажем) Standard ML, хотя все они работают в самых разных системах.
ruakh
2
Стоит упомянуть, что это задокументировано в спецификации Java : «Язык программирования Java использует представление двух дополнений для целых чисел, а диапазон значений дополнения до двух не является симметричным, поэтому отрицание максимального отрицательного int или long приводит к тому же максимуму. отрицательное число."
chesterbr
25

Ценность, которую вы ищете Integer.MIN_VALUE.


Я также хотел бы получить алгебраическое доказательство того, какой ответ это условие имеет (в контексте с java)?

Это не по теме для Stack Exchange. Но вы могли бы сделать это, начиная с определения целых чисел Java ( JLS 4.2 )

«Целочисленные типы - это byte, short, int и long, значения которых - 8-битные, 16-битные, 32-битные и 64-битные целые числа с дополнением до двух со знаком ...»

и

"Значения целочисленных типов являются целыми числами в следующих диапазонах ... Для int от -2147483648 до 2147483647 включительно"

и определение унарного оператора Java '-' ( JLS 15.15.4 ):

"Для целочисленных значений отрицание аналогично вычитанию из нуля. В языке программирования Java для целых чисел используется представление с дополнением до двух, а диапазон значений с дополнением до двух несимметричен, поэтому отрицание максимального отрицательного int или long приводит к тому, что такое же максимальное отрицательное число. В этом случае происходит переполнение, но исключение не возникает. Для всех целых значений x, -x равно (~ x) +1. "

Стивен С
источник
3
Также Long.MIN_VALUE .
Juvanis
1
что составляет 100000 .., и если я получу 2 комплимента из этого, это снова 011111 ... + 1 = 100000 ... но вы знаете это в голове, или мы можем применить любую логику?
Sunny
1
Поскольку я прочитал ... арифметика int java - это арифметический мод 2power32, поэтому я подумал, сможем ли мы доказать это значение всего за 1 или 2 строки ... если это большое доказательство ... тогда нет проблем.
Sunny
2
@Sunny это не так уж сложно доказать. В целочисленном диапазоне все положительные числа имеют отрицательный аналог (так i != -i). В диапазоне остаются два числа: 0и Integer.MIN_VALUE. Из-за того, что i != 0в вашем случае остается только MIN_VALUE.
Vincent van der Weele
1
@Heuster - это рассуждение работает ... но это зависит от одного или двух предположений, требующих доказательства.
Stephen C
18

В дополнение к ответам, данным до сих пор ...

Всего существует четыре значения

int i = Integer.MIN_VALUE;
long i = Long.MIN_VALUE;
Integer i = Integer.valueOf(Integer.MIN_VALUE);
Long i = Long.valueOf(Long.MIN_VALUE);

Обернутые значения разворачиваются, поэтому они также верны для этого выражения.

Примечание: документы Math.abs.

общедоступный статический int abs (int a)

Возвращает абсолютное значение типа int. Если аргумент не отрицательный, возвращается аргумент. Если аргумент отрицательный, возвращается отрицание аргумента.

Обратите внимание, что если аргумент равен значению Integer.MIN_VALUE, наиболее отрицательному представимому значению int, результатом будет то же самое значение, которое является отрицательным.

и

публичный статический длинный пресс (длинный а)

Возвращает абсолютное значение длинного значения. Если аргумент не отрицательный, возвращается аргумент. Если аргумент отрицательный, возвращается отрицание аргумента.

Обратите внимание, что если аргумент равен значению Long.MIN_VALUE, наиболее отрицательному представимому длинному значению, результатом будет то же самое значение, которое является отрицательным.

Удивительно, что Math.abs может возвращать отрицательное число. Это происходит либо потому, что: а) в этих случаях нет положительных значений для -MIN_VALUE; б) выполнение -вычислений приводит к переполнению.

Интересно также, почему этого не делают Byte.MIN_VALUE, Short.MIN_VALUE. Это связано с тем, что для них -изменяется тип, intи, следовательно, нет переполнения.

Character.MIN_VALUE не имеет проблем, потому что он равен 0.

Float.MIN_VALUE и Double.MIN_VALUE имеют разное значение. Это наименьшее представимое значение больше нуля. Таким образом, они имеют действительные отрицательные значения, которые не являются самими собой.

Питер Лоури
источник
1
Мне было интересно узнать о Byte.MIN_VALUE и других возможностях, ваш ответ предоставил это. Спасибо
Дженгиз
14

Как уже упоминалось другими, это выполняется только Integer.MIN_VALUE. Что касается доказательства, позвольте мне предложить более легкое для понимания объяснение, отличное от двоичного (хотя оно все еще основано на этом).

Обратите внимание, что Integer.MIN_VALUEэто равно -2^31или -2147483648и Integer.MAX_VALUEравно 2^31-1или 2147483647. -Integer.MIN_VALUEis 2^31, которое теперь слишком велико для целого числа (поскольку оно прошло MAX_VALUE), что вызывает переполнение целого числа, что делает его Integer.MIN_VALUEснова. Это единственное целое число, которое делает это, поскольку MIN_VALUEэто единственное число без отрицательного эквивалента, кроме 0.

Марк М
источник
2
@dystroy на самом деле я искал какое-то объяснение, согласно Марку, такого числа, как +2147483648, в диапазоне int нет, поэтому первым подозреваемым должно быть это число, отличное от 0. Диапазон от -2 ^ n до 2 ^ n-1. Таким образом, нет положительного аналога -2 ^ n. Это всего лишь еще одно возможное значение int.
Sunny
1
Я не объяснял в двоичном формате, поскольку он уже был покрыт кем-то другим (в основном int - это 32-битное значение, поэтому у него есть эти ограничения). Кроме того, отрицательное или отрицательное значение является положительным, поэтому условия все еще могут применяться.
Mark M
1
Как ни странно, в Java число 2147483648может появляться в исходном коде только в одном случае: как операнд унарного оператора минус (JLS 3.10.1).
Eric Jablow
6

Предварительное алгебраическое доказательство с использованием modulo 2^32арифметики:

i == -iможно переписать как 2 * i == 0(добавляя iс обеих сторон), или i << 1 == 0.

Это уравнение имеет два решения вида i == 0 >> 1: 0bи, 10000000000000000000000000000000bполучаемые сдвигом влево 0или 1вправо.

Решение i == 0исключено, остается решение i == 100000000000000000000000000000000b.

Ив Дауст
источник
0

Возможно, это не слишком поучительно, но вместо того, чтобы думать, что вы можете запустить этот код:

    for (int i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i++)
    {
        if (i == -i && i != 0)
        {
            System.out.println(i);
        }
    }

чтобы увидеть, что он печатает

-2147483648
-2147483648

бесконечно :)

Куба
источник
Как вы думаете, это бесконечно?
JBelter
Потому что i <= Integer.MAX_VALUE никогда не будет ложным
Куба
1
Ах, очень верно, думал, что видел строго<
JBelter