Wartość i dla (i == -i && i! = 0), aby zwrócić prawdę w Javie


101

Mam następujący ifwarunek.

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

Jaka wartość izwróci trueten warunek w Javie?

Nie przychodzi mi do głowy żadna taka wartość irozważania notacji dopełniającej do dwóch w Javie.

Chciałbym również mieć algebraiczny dowód na jakąkolwiek odpowiedź ma ten warunek (w kontekście Java)?


2
co powiesz na if (i! = null)
zxc

4
Zauważ, że -0.0to również== 0
Peter Lawrey,

2
napisz to jakoif(i && i == -i)
Grijesh Chauhan

10
@GrijeshChauhan W Javie? Jesteś pewny ?
Denys Séguret

3
@harold Wielokrotnie pytałem o to w wywiadach w ciągu ostatnich czterech lat i niewiele osób naprawdę to rozumie, nawet mając podpowiedzi.
Peter Lawrey,

Odpowiedzi:


126

Jedyną intwartością, dla której to działa, jest Integer.MIN_VALUE.

Dzieje się tak, ponieważ liczby całkowite są negowane przy użyciu sposobu dopełniania do dwóch .

Za pomocą

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

widzisz, że Integer.MIN_VALUEto jest

10000000000000000000000000000000

Przyjmowanie wartości ujemnej odbywa się przez pierwszą zamianę 0i 1, co daje

01111111111111111111111111111111

i dodając 1, co daje

10000000000000000000000000000000

Jak widać w linku, który podałem, Wikipedia wspomina o problemie z większością liczb ujemnych i określa, że ​​jest to jedyny wyjątek:

Najbardziej ujemna liczba w uzupełnieniu do dwóch jest czasami nazywana „dziwną liczbą”, ponieważ jest to jedyny wyjątek.

Oczywiście masz to samo zjawisko, Long.Min_Valuejeśli przechowujesz je w longzmiennej.

Zauważ, że jest to spowodowane tylko wyborami, które zostały podjęte odnośnie binarnego przechowywania int w Javie . Innym (złym) rozwiązaniem mogłoby być na przykład zanegowanie poprzez po prostu zmianę najbardziej znaczącego bitu i pozostawienie pozostałych bitów niezmienionych. Pozwoliłoby to uniknąć problemu z MIN_VALUE, ale spowodowałoby 2 różne 0wartości i skomplikowaną arytmetykę binarną (jak byś zwiększona np.?).


2
Warto zauważyć, że wczesne komputery binarne używały implementacji znaku i wielkości dla liczb całkowitych opisanych w ostatnim akapicie; podobnie jak liczby zmiennoprzecinkowe IEE754. en.wikipedia.org/wiki/…
Dan Is Fiddling By Firelight

1
Re: „dotyczy to tylko wyborów, które zostały dokonane w odniesieniu do binarnego przechowywania intów”: Oraz wyborów dotyczących sposobu obsługi przepełnienia. Reguła, której używa Java, nie jest tym samym, co reguła używana przez (powiedzmy) C lub regułę używaną przez (powiedzmy) Standard ML, mimo że wszystkie z nich działają w wielu różnych systemach.
ruakh

2
Warto wspomnieć, że jest to udokumentowane w specyfikacji Java : „Język programowania Java używa reprezentacji dopełnienia do dwóch dla liczb całkowitych, a zakres wartości uzupełnień do dwóch nie jest symetryczny, więc negacja maksymalnej ujemnej wartości int lub long powoduje to samo maksimum Liczba ujemna."
chesterbr

25

Wartość, której szukasz, to Integer.MIN_VALUE.


Chciałbym również mieć algebraiczny dowód na odpowiedź, jaką ma ten warunek (w kontekście javy)?

To nie jest tematem do wymiany stosów. Ale możesz to zrobić, zaczynając od definicji liczb całkowitych Java ( JLS 4.2 )

„Typy całkowite to bajt, short, int i long, których wartości to 8-bitowe, 16-bitowe, 32-bitowe i 64-bitowe liczby całkowite uzupełnione do dwóch ze znakiem ...”

i

„Wartości typów całkowitych są liczbami całkowitymi w następujących zakresach ... Dla int, od -2147483648 do 2147483647 włącznie”

oraz definicja jednoargumentowego operatora Java ( JLS 15.15.4 ):

„W przypadku wartości całkowitych negacja jest tym samym, co odejmowanie od zera. Język programowania Java używa reprezentacji uzupełnień do dwóch dla liczb całkowitych, a zakres wartości uzupełnień do dwóch nie jest symetryczny, więc negacja maksymalnej ujemnej wartości int lub long powoduje, że ta sama maksymalna liczba ujemna. W tym przypadku występuje przepełnienie, ale nie jest zgłaszany żaden wyjątek. Dla wszystkich wartości całkowitych x, -x równa się (~ x) +1. "


3
Również długi.MIN_VALUE .
Juvanis

1
czyli 100000 ..., a jeśli otrzymam komplement 2, to znowu jest 011111 ... + 1 = 100000 ... ale wiesz, jak to wygląda, czy możemy zastosować jakąkolwiek logikę?
Sunny

1
Jak przeczytałem, arytmetyka int Javy to arytmetyczny mod 2power32, więc zastanawiałem się, czy możemy udowodnić tę wartość w zaledwie 1 lub 2 wierszach ... jeśli to duży dowód ... to nie ma problemu.
Sunny

2
@Sunny to nie może być trudne do udowodnienia. W zakresie liczb całkowitych wszystkie liczby dodatnie mają ujemny odpowiednik (więc i != -i). To pozostawia dwie liczby w zakresie: 0i Integer.MIN_VALUE. Z powodu i != 0twojego „if” MIN_VALUEzostaje tylko .
Vincent van der Weele

1
@Heuster - to rozumowanie działa ... ale zależy od jednego lub dwóch założeń, które wymagają dowodu.
Stephen C

18

Oprócz dotychczas udzielonych odpowiedzi ...

W sumie są cztery wartości

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

Opakowane wartości są rozpakowywane, więc są również prawdziwe dla tego wyrażenia.

Uwaga: dokumenty Math.abs.

public static int abs (int a)

Zwraca wartość bezwzględną wartości int. Jeśli argument nie jest ujemny, zwracany jest argument. Jeśli argument jest ujemny, zwracana jest negacja argumentu.

Zwróć uwagę, że jeśli argument jest równy wartości Integer.MIN_VALUE, czyli najbardziej ujemnej wartości typu int, wynikiem jest ta sama wartość, która jest ujemna.

i

publiczne statyczne długie mięśnie brzucha (długie a)

Zwraca wartość bezwzględną wartości długiej. Jeśli argument nie jest ujemny, zwracany jest argument. Jeśli argument jest ujemny, zwracana jest negacja argumentu.

Zauważ, że jeśli argument jest równy wartości Long.MIN_VALUE, czyli wartości długiej, która jest najbardziej ujemna do reprezentacji, wynikiem jest ta sama wartość, która jest ujemna.

Zaskakujące jest to, że Math.abs może zwrócić liczbę ujemną. Dzieje się tak, ponieważ a) nie ma dodatnich wartości -MIN_VALUE w tych przypadkach b) wykonanie- obliczeń skutkuje przepełnieniem.

Interesujące jest również to, dlaczego Byte.MIN_VALUE, Short.MIN_VALUE tego nie robią. Dzieje się tak, ponieważ -zmienia się typ naint na te, a zatem nie ma przepełnienia.

Character.MIN_VALUE nie ma problemu, ponieważ wynosi 0.

Float.MIN_VALUE i Double.MIN_VALUE mają inne znaczenie. Są to najmniejsze możliwe do przedstawienia wartości większe od zera. W ten sposób mają ważne wartości ujemne, które nie są sobą.


1
Zastanawiałem się nad Byte.MIN_VALUE i innymi możliwościami, Twoja odpowiedź była taka. Dzięki
Cengiz może

14

Tak jak wspominali inni, jest to spełnione tylko przez Integer.MIN_VALUE. Jeśli chodzi o dowód, pozwólcie, że przedstawię łatwiejsze do zrozumienia wyjaśnienie inne niż binarne (chociaż nadal jest na tym zakorzenione).

Zauważ, że Integer.MIN_VALUEjest równe -2^31lub -2147483648i Integer.MAX_VALUEjest równe 2^31-1lub 2147483647. -Integer.MIN_VALUEjest 2^31, która jest teraz zbyt duża dla liczby całkowitej (ponieważ jest przeszłością MAX_VALUE), powodując przepełnienie liczby całkowitej, co powoduje jej Integer.MIN_VALUEponowne. Jest to jedyna liczba całkowita, która to robi, ponieważ MIN_VALUEjest jedyną liczbą bez ujemnego odpowiednika poza 0.


2
@dystroy właściwie szukałem jakiegoś wyjaśnienia, według Marka, nie ma takiej liczby jak +2147483648 w zakresie int, więc pierwszym podejrzanym powinna być ta liczba inna niż 0. Zakres wynosi od -2 ^ n do 2 ^ n-1. Nie ma więc dodatniego odpowiednika -2 ^ n. To tylko kolejna możliwa wartość int.
Sunny

1
Nie wyjaśniałem w binarnym, ponieważ był już pokryty przez kogoś innego (w zasadzie int to wartość 32-bitowa, dlatego ma te ograniczenia). Negatywne lub negatywne jest również pozytywne, więc warunki mogą nadal obowiązywać.
Mark M

1
Co dziwne w Javie, liczba 2147483648może pojawić się w kodzie źródłowym tylko w jednym przypadku: jako operand jednoargumentowego operatora minus (JLS 3.10.1).
Eric Jablow

6

Wstępny dowód algebraiczny, używając modulo 2^32arytmetyki:

i == -imożna przepisać jako 2 * i == 0(dodając ipo obu stronach) lub i << 1 == 0.

Równanie ma dwa rozwiązania postaci i == 0 >> 1, a mianowicie 0b, a 10000000000000000000000000000000botrzymywana jest poprzez przesunięcie w jednej 0lub 1w lewo.

Po i == 0wykluczeniu rozwiązania pozostaje rozwiązanie i == 100000000000000000000000000000000b.


0

Może nie jest to zbyt edukacyjne, ale zamiast myśleć, że możesz uruchomić ten kod:

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

żeby zobaczyć, że to drukuje

-2147483648
-2147483648

nieskończenie :)


Jak myślisz, że to nieskończenie?
JBelter,

Ponieważ i <= Integer.MAX_VALUE nigdy nie będzie fałszywe
Kuba

1
Ach, bardzo prawda, myślałem, że widziałem dokładnie<
JBelter
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.