Значення i для (i == -i && i! = 0) повертає істину в 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)
Гріеш Чаухан

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змінній.

Зауважте, що це пов'язано лише з вибором, який було зроблено стосовно двійкового зберігання вкладень на Java . Іншим (поганим) рішенням можна було, наприклад, відмовитись, просто змінивши найзначніший біт і залишивши інші біти незмінними, це дозволило б уникнути цієї проблеми з MIN_VALUE, але зробило б 2 різні 0значення та складну двійкову арифметику (як би ви мали збільшується, наприклад?).


2
Варто зазначити, що ранні двійкові комп'ютери використовували реалізацію знаків та величин для цілих чисел, описаних у вашому останньому абзаці; як і цифри з плаваючою комою IEE754 en.wikipedia.org/wiki/…
День вигадує Firelight

1
Re: "Це пов'язано лише з вибором, який було зроблено щодо двійкового зберігання вкладених даних": І вибір способів обробки переповнення. Правило, яке використовує Java, не є тим самим, як правило, яке використовується (скажімо) C, або правило, яке використовує (скажімо) стандартний ML, навіть якщо всі вони працюють на широких різновидах систем.
ruakh

2
Варто зазначити, що це документально зафіксовано на Java Spec : "Мова програмування Java використовує представлення двох доповнень для цілих чисел, а діапазон значень доповнення двох не є симетричним, тому заперечення максимального від'ємного int або тривалого призводить до того самого максимуму від’ємне число ”.
честербр

25

Значення, яке ви шукаєте, - це Integer.MIN_VALUE.


Я також хотів би мати алгебраїчний доказ будь-якої відповіді на цю умову (в контексті java)?

Це поза темою для обміну стеками. Але ви могли це зробити, починаючи з визначення цілих чисел Java ( JLS 4.2 )

"Цілісні типи - це байт, короткий, int та long, значення яких 8-бітні, 16-бітні, 32-бітні та 64-бітні, підписані двома цілими числами-доповненнями ..."

і

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

та визначення оператора Java unary '-' ( JLS 15.15.4 ):

"Для цілих значень заперечення - це те саме, що віднімання від нуля. Мова програмування Java використовує подання двох доповнень для цілих чисел, а діапазон значень двох доповнення не є симетричним, тому заперечення максимального від'ємного int або довгих результатів у цьому таке ж максимальне від’ємне число. У цьому випадку відбувається переповнення, але не виняток. Для всіх цілих значень x, -x дорівнює (~ x) +1. "


3
Довго.MIN_VALUE також.
Юваніс

1
що становить 100000 .., і якщо я отримаю комплімент 2, це знову 011111 ... + 1 = 100000 ... але ви знаєте це вгорі голови або ми можемо застосувати будь-яку логіку?
Сонячний

1
Як я читав .. середня арифметика - це арифметична мода 2power32, тому я думав, чи зможемо ми довести це значення лише за 1 або 2 рядки ...
Сонячний

2
@Sunny це не може бути занадто важким для доказу. У цілому діапазоні всі додатні числа мають від’ємний аналог (так i != -i). Це залишає два числа в діапазоні: 0і Integer.MIN_VALUE. Тому що i != 0у вашому, якщо, залишилося тільки MIN_VALUE.
Вінсент ван дер Веель

1
@Heuster - це міркування працює ... але це залежить від припущення чи двох, які потребують доказів.
Стівен С

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.

public static int abs (int a)

Повертає абсолютне значення значення int. Якщо аргумент не є негативним, аргумент повертається. Якщо аргумент негативний, заперечення повертається.

Зауважимо, що якщо аргумент дорівнює значенню Integer.MIN_VALUE, найбільш негативне представне значення int, то результат - це те саме значення, яке є негативним.

і

публічний статичний довгий abs (довгий a)

Повертає абсолютне значення довгого значення. Якщо аргумент не є негативним, аргумент повертається. Якщо аргумент негативний, заперечення повертається.

Зауважте, що якщо аргумент дорівнює значенню Long.MIN_VALUE, найбільш негативне представлене довге значення, то результат - це те саме значення, яке є негативним.

Дивно, що Math.abs може повернути від’ємне число. Це відбувається або тому, що: a) немає позитивних значень для -MIN_VALUE у цих випадках; b) виконання- обчислення призводить до переповнення.

Цікавить також те, чому Byte.MIN_VALUE, Short.MIN_VALUE цього не роблять. Це відбувається тому, що -змінюється тип наint для цих, і тому немає переповнення.

У символу.MIN_VALUE не виникає проблем, оскільки це 0.

Float.MIN_VALUE і Double.MIN_VALUE мають різне значення. Це найменше представлене значення, що перевищує нуль. Таким чином, вони мають дійсні негативні значення, які не є самими собою.


1
Мені було цікаво про Байт.MIN_VALUE та інші можливості, ваша відповідь передбачала це. Спасибі
Cengiz Can

14

Як і інші, які згадували, це лише виконує Integer.MIN_VALUE . Щодо доказів, дозвольте запропонувати більш легке для розуміння пояснення, окрім як у двійковому (хоча воно все ще входить у це).

Зверніть увагу , що Integer.MIN_VALUEдорівнює -2^31або -2147483648й Integer.MAX_VALUEдорівнює 2^31-1або 2147483647. -Integer.MIN_VALUEє 2^31, який зараз занадто великий для цілого (оскільки він минув MAX_VALUE), таким чином викликаючи переповнення Integer, роблячи його Integer.MIN_VALUEзнову. Це єдине ціле число, яке робить це, оскільки MIN_VALUEце єдине число, у якому немає 0 негативного еквівалента.


2
@dystroy насправді я шукав пояснення, згідно Марку, немає такої кількості, як +2147483648 в діапазоні int, тому першим підозрюваним має бути це число, крім 0. Діапазон від -2 ^ n до 2 ^ n-1. Тож немає позитивного аналога на -2 ^ n. Це лише інше можливе значення int.
Сонячний

1
Я не пояснював у двійковій формі, оскільки її вже охоплював хтось інший (в основному, int - це 32-бітове значення, тому він має ці межі). Також негатив негативу є позитивним, тому умови все ще можуть застосовуватися.
Марк М

1
Як не дивно в Java, число 2147483648може з'являтися у вихідному коді лише за однієї обставини: як операнд оператора унарного мінусу (JLS 3.10.1).
Ерік Яблов

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 ніколи не буде помилковим
Kuba

1
Ага дуже правдиво, думав, що я бачив суворо<
JBelter
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.