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.