Jak można „while (i == i);” być niekończącą się pętlą w aplikacji jednowątkowej?


141

Właśnie dostałem pytanie, na które nie mogę odpowiedzieć.

Załóżmy, że masz tę definicję pętli w Javie:

while (i == i) ;

Jaki jest typ ii wartość, ijeśli pętla nie jest nieskończoną pętlą, a program używa tylko jednego wątku ?


7
och, na litość boską, czy ludzie mieliby zaszczyt komentować, dlaczego głosują przeciw? to jest oznaczone jako zagadka, w czym problem ???
user54579

10
Myślę, że niektórzy ludzie nie mogą przestać głosować za niczym.
FerranB

1
Ach, przepraszam, że to spowodowałem: / Naprawdę chciałem tylko odpowiedzi i nie mogłem sam tego rozwiązać.
Zizzencs

1
@nickolai, taka jest natura SO - przegłosowanie typu drive-by down jest niestety rzeczywistością, a pomysł wymagania komentarza został przedyskutowany i odrzucony. Ale wygląda na to, że „społeczność” w końcu popiera to pytanie.
paxdiablo

1
Jedną ze sztuczek tego rodzaju pytań jest to, że ludzie przyjmują typ pewnych nazw zmiennych, tj. I to int, d to double, s to string lub short, ch to char, l to long, b jak bajt lub wartość logiczna. Musisz zadać sobie pytanie, jaki typ jest sugerowany i jaki może to być.
Peter Lawrey,

Odpowiedzi:


125
double i = Double.NaN;

API dla Double.equals () podaje odpowiedź: „Double.NaN == Double.NaN ma wartość false”. Jest to omówione w specyfikacji języka Java w sekcji „ Typy zmiennoprzecinkowe, formaty i wartości ”:

NaNjest nieuporządkowana, więc numeryczna operatory porównania <, <=, >, i >= powrotu falsejeżeli jeden lub oba argumenty są NaN. Operator równości ==zwraca, falsejeśli którykolwiek z operandów jest NaN, a operator nierówności !=zwraca, truejeśli którykolwiek z operandów to NaN. W szczególności x!=xjest truewtedy i tylko wtedyxNaN , gdy jest i (x<y) == !(x>=y)będzie, falsejeśli xlub ybędzie NaN.


1
O, więc MOŻESZ zrobić „Not a Number”!
Filip Ekberg

12
jest matematycznie solidny, dlaczego jedna liczba nierzeczywista miałaby być równa drugiej? 5/0! = Sqrt (-4)
Gordon Gustafson

2
@CrazyJugglerDrummer: Może, ale x == xzawsze powinno być prawdą. Dlaczego nic nie miałoby się równać?
Bart van Heukelom

1
Bart: ponieważ tak naprawdę nieznane nie zawsze oznacza nieznane. Czasami jest to przydatne, dlatego bazy danych mają NULL ...
Konerak

2
@inovaovao: nie, w bazie danych null=nullma wartość null. NULL IS NULLjest 1.
Konerak

29

Wartość ijest wtedy nieprawidłowa. „To nie jest numer”.

Po pewnym googlowaniu odkryłem, że MOŻESZ mieć NaN (Not a Number) w Javie! Zatem liczba zmiennoprzecinkowa jest typem danych, a wartością jest NaN. Zobacz tutaj


12
Tak, to wszystko. Wartość i to Jon Skeet.
Andrew Rollings

Generalnie nienawidzę ludzi, którzy głosują przeciw bez powodu ... Byłem pierwszym, który powiedział „To nie jest numer”, ale nie sądziłem, że java sobie z tym poradzi, ponieważ nie obsługuje niczego innego, fajnego.
Filip Ekberg



8

Nie jestem pewien, ale uważam, że (i == i) nie jest operacją atomową w procesie wielowątkowym, więc jeśli wartość i zostanie zmieniona przez inny wątek między wypchnięciami jej wartości do stosu w wątku wykonującym pętlę, wówczas ten warunek może być fałszywe.


8

Ponieważ inni powiedzieli, że to NaN, zaciekawiło mnie oficjalne (JDK 6) wdrożenie Double.isNaNi oto:

/**
 * Returns <code>true</code> if the specified number is a
 * Not-a-Number (NaN) value, <code>false</code> otherwise.
 *
 * @param   v   the value to be tested.
 * @return  <code>true</code> if the value of the argument is NaN;
 *          <code>false</code> otherwise.
 */
static public boolean isNaN(double v) {
    return (v != v);
}

2

Pomyśl o Nan jako o ekwiwalencie wyjątku, ale używaj wartości magicznej w obliczeniach. Ponieważ obliczenia nie powiodły się - np. Pierwiastek kwadratowy z wartości ujemnej, podzielenie przez zero itd. - nie ma sensu porównywać ich z czymkolwiek innym. W końcu jeśli dzielenie przez zero to nan, to czy jest to równoważne pierwiastkowi kwadratowemu z -2 czy pierwiastkowi kwadratowemu z -3?

Nan umożliwia obliczenia, które obejmują krok, który zwraca nieprawidłową odpowiedź do wykonania bez wprowadzania dodatkowych wyjątków. Aby sprawdzić, czy odpowiedź brzmi: po prostu przetestuj pod kątem braku nandness (czy to jest słowo, jeśli nie mam go w worku) za pomocą równoważnika Float.isNan ().


3
Byłoby łatwiej myśleć o tym jako o wyjątku, ale gdybym naprawdę wiedział, co to był wyjątek :-).
paxdiablo

2

dodałbym

float i = Float.NaN;

jak również

double i = Double.NaN;

Typowa sztuczka w tego rodzaju pytaniach polega na założeniu, że ja jest int. Inne typowe założenia to: s to String, x, y to double, ch to char, b to byte itd. Jeśli zobaczysz takie pytanie, możesz się założyć, że „i” nie jest jego oczekiwanym typem.

Podobne pytanie brzmi; To nigdy się nie zapętla, co to jest 'x'

while(x == x && x != x + 0) { }

Kolejne pytanie, które bardzo mi się podoba, to; Ta pętla jest nieskończoną pętlą, jakie są możliwe wartości x. (: Naliczam ich dwanaście :)

while(x != 0 && x == -x) { }

0

Wiem, że jest to pytanie dotyczące języka Java, ale rozważenie tego pytania dla innych języków jest intrygujące.

W C prosty typ, taki jak „int”, mógłby się zakończyć, zanim wszechświat ostygnie, zachowanie, jeśli „i” zostało zadeklarowane jako zmienne (więc kompilator byłby zmuszony do wykonania dwóch odczytów „i” dla każdej iteracji) i jeśli „i” rzeczywiście było w pamięci, gdzie coś innego mogłoby na to wpłynąć. Następnie pętla zakończyłaby się, gdy „i” zmieniło się między dwoma odczytami jednej iteracji. ( Dodano : możliwe miejsce - w mikrokomputerze, gdzie „i” faktycznie znajduje się pod adresem portu I / O, być może podłączone do czujnika położenia. Byłoby bardziej prawdopodobne, gdyby „i” było zmienną wskaźnikową ( wskaźnik do pamięci ulotnej), a instrukcja brzmiała ' while (*i == *i);'.)

Jak pokazują inne odpowiedzi, w C ++ operator „==” może być dostarczony przez użytkownika, jeśli i należy do klasy zdefiniowanej przez użytkownika, więc wszystko może być możliwe.

Podobnie jak NaN, w języku opartym na SQL pętla nie byłaby nieskończona, gdyby wartość i wynosiła NULL; jednak każda wartość inna niż NULL sprawiłaby, że pętla byłaby nieskończona. Jest to raczej podobne do Javy, gdzie dowolna liczba (w przeciwieństwie do NaN) sprawia, że ​​pętla jest nieskończona.

Nie sądzę, aby konstrukt miał jakiekolwiek praktyczne zastosowanie, ale jest to interesujące pytanie o ciekawostkę.


0

Byłem zaskoczony, że nie widziałem tego rozwiązania:

while (sin(x) == sin(x)) //probably won't eval to true

W odpowiedzi na komentarz spróbuj uruchomić to:

double x = 10.5f;
assert (x == asin(sin(x)));

x powinno zawsze być równe arcus sinus (sin (x)) w teorii, ale w praktyce tak nie jest.


3
Dlaczego nie? Wykonujesz dokładnie te same obliczenia na dokładnie tych samych danych, oba wyniki będą zawierać dokładnie ten sam błąd.
Loren Pechtel,

Nie pamiętam dokładnie, gdzie go przeczytałem, ale w zależności od maszyny / implementacji sin (x) w jednym wywołaniu funkcji ma znikomą szansę zrównania się z sin (x) innego wywołania. Ma to związek z dokładnością cyfr zmiennoprzecinkowych (coś szczególnego w funkcjach trygonometrycznych sprawia, że ​​nie zwracają one dwukrotnie tej samej wartości).
jkeys

Zobacz moją aktualizację. Arcus sinus „cofa” grzech x, więc powinny być równe, ale tak nie jest.
jkeys

To nie to samo. Jak powiedział Loren, wykonujesz dokładnie tę samą operację x, która powinna dać dokładnie ten sam wynik z dokładnie taką samą niedokładnością. Arcsin nie może odwrócić wyniku grzechu za pomocą liczb zmiennoprzecinkowych, ponieważ przekazana wartość asin()nie będzie dokładnie dokładna. Dlatego wynik asin()będzie niedokładny i x == asin(sin(x))fałszywy. Ponadto arcsin niekoniecznie „cofa” operację sin - funkcja sin może dać ten sam wynik dla wielu wartości x, dlatego asin()zwraca tylko liczby między -π / 2 a π / 2.
hbw

2
Innymi słowy, arcsin nie zawsze może „cofnąć” funkcję sin, ponieważ arcsin nie może wiedzieć, jaki był pierwotny kąt. Na przykład, grzech zarówno π / 2, jak i 5π / 2 daje 1. Ale co to jest arcsin (1)? To oczywiście nie może oddać obu, prawda? Dlatego wynik arcsin musi być ograniczony do zakresu 2π radianów, co oznacza, że ​​nie może faktycznie cofnąć wyniku funkcji sin, chyba że pierwotny kąt jest między 0 a 2π, lub w przypadku C -π / 2 i π / 2. (Rzeczywiście, arcsin (sin (5π / 2)) = π / 2.) W każdym razie to było naprawdę długie wyjaśnienie, ale mam nadzieję, że pomoże to wyjaśnić wszelkie nieporozumienia.
hbw

0

Nie nieskończona pętla, jeden wątek :)

import static B.*;
public class A {
    public static void main(String[] args) {
        System.out.println("Still Running");
        while (i == i) ;
    }
}


public class B {

    public static int i;
    static {
        System.exit(0);
    }
}

-1

i == inie jest atomowy. Udowodniony przez taki program:

static volatile boolean i = true;
public static void main(String[] args) throws InterruptedException
{
    new Thread() {
        @Override
        public void run() {
            while (true) {
                i = !i;
            }
        }
    }.start();

    while (i == i) ;
    System.out.println("Not atomic! i: " + i);
}

Aktualizacja Oto jeszcze jeden przykład nieskończonej pętli (nie są tworzone żadne nowe wątki).

public class NoNewThreads {
    public static void main(String[] args) {
        new NoNewThreads();
        System.gc();
        int i = 500;
        System.out.println("Still Running");
        while (i == i) ;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        Thread.sleep(1000);
        System.exit(0);
    }
}

@Charles Goodwin Co powiesz na to, że nie ma możliwości napisania programu w Javie przy użyciu jednego wątku :), więc wszystkie inne rozwiązania wykorzystują co najmniej dwa wątki (dokładnie tak samo jak mój drugi program w dziale 'Aktualizacja').
Andrey

To nie jest przerwanie pętli. Każdy kod później while (i == i);nie zostanie wykonany.
aalku

Finalize wykorzystuje inny wątek, ale warto o tym wspomnieć. To jest powód, dla którego pierwotne pytanie brzmiało „a program używa tylko jednego wątku”… w pewnym sensie wyraźnie stwierdzając, że jest to oczywista odpowiedź i chcieliby, abyś spojrzał dalej.
Bill K
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.