“While (i == i);” nasıl olabilir? iş parçacıklı uygulamada sonsuz olmayan bir döngü olabilir mi?


141

Sadece cevaplayamadığım bir sorum var.

Java'da bu döngü tanımına sahip olduğunuzu varsayalım:

while (i == i) ;

Döngü sonsuz bir döngü değilse ve program yalnızca bir iş parçacığı kullanıyorsa türü ive değeri nedir?i


7
Tanrı aşkına, insanlar neden aşağı düştüklerine dair yorum yapmaktan onur duyarlar mı? bu bir bilmece olarak etiketlenir, sorun nedir ???
user54579

10
Bence bazı insanlar hiçbir şey için aşağıya vuramazlar.
FerranB

1
Bah, buna sebep olduğum için özür dilerim: / Cevabı gerçekten istedim ve kendim çözemedim.
Zizzencs

1
@nickolai, bu SO'nın doğası - aşağı yönde oy verme maalesef bir gerçek ve bir yorum isteme fikri tartışıldı ve reddedildi. Ama görünüşe göre "topluluk" bu sorunun lehine.
paxdiablo

1
Bu tür bir sorunun hilelerinden biri, insanların belirli değişken isimlerinin türünü almasıdır, yani i bir int, d bir çift, s bir dize veya kısa, ch bir char, l uzun, b bayt veya boole. Kendinize hangi türün önerildiğini ve ne olabileceğini sormalısınız.
Peter Lawrey

Yanıtlar:


125
double i = Double.NaN;

Double.equals () için API şu cevabı belirtir: "Double.NaN == Double.NaN, false değerine sahiptir". Java Dil Belirtimi'nde " Kayan Nokta Türleri, Biçimler ve Değerler " başlığı altında ele alınmıştır :

NaNSayısal karşılaştırma operatörleri, böylece sırasız <, <=, >ve >= geri dönüş falseya da her iki işlenen ise NaN. Eşitlik operatörü ==döner falseya işlenen ise NaN, ve eşitsizlik operatörü !=döner trueya işlenen ise NaN. Özellikle, x!=xolup trueancak ve ancak xISNaN ve (x<y) == !(x>=y)olacak falseeğer xyoksa yolduğunu NaN.


1
OH böylece "Sayı değil" yapabilirsiniz!
Filip Ekberg

12
matematiksel olarak sağlam, gerçek olmayan bir sayı neden diğerine eşit olsun ki? 5/0! = Sqrt (-4)
Gordon Gustafson

2
@CrazyJugglerDrummer: Belki, ama aynı şekilde x == xher zaman doğru olmalıdır. Neden bir şey kendisine eşit olmasın?
Bart van Heukelom

1
Bart: Çünkü gerçekten, bilinmeyen her zaman bilinmeyene eşit değildir. Bazen yararlıdır, bu yüzden veritabanlarında NULL vardır ...
Konerak

2
@inovaovao: hayır, bir DB'de null=nullnull. NULL IS NULL1
Konerak

29

Değeri igeçersizdir. Msgstr "Sayı Değil".

Bazı googling sonra, Java NaN (değil bir sayı) olabilir öğrendim! Dolayısıyla, bir Kayan Nokta numarası Veri Türü ve Değer NaN'dir. Buraya bakın


12
Evet, hepsi bu. İ'nin değeri Jon Skeet.
Andrew Rollings

Genelde sebepsiz yere inen insanlardan nefret ediyorum ... "Sayı Değil" diyen ilk kişiydim ama java'nın bunu başarabileceğini düşünmedim, çünkü başka bir şeyle başa çıkmıyor.
Filip Ekberg



8

Emin değilim, ama inanıyorum (i == i) çok iş parçacıklı işlemde atomik işlem değildir, bu yüzden i değeri döngü yürütme iş parçacığına yığmak için değeri iter arasında diğer iş parçacığı tarafından değiştirilecek, o zaman bu koşul olabilir yanlış olmak.


8

Diğerleri NaN olduğunu söylediğinden, resmi (JDK 6) uygulamasını merak ettim ve şunları görüyorum Double.isNaN:

/**
 * 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

Nan'i istisnaya eşdeğer olarak düşünün, ancak hesaplamada sihirli bir değer kullanın. Bir hesaplama başarısız olduğu için (örneğin, negatifin karekökü, sıfıra bölme vb.), Bunları başka bir şeyle karşılaştırmak mantıklı değildir. Sonuçta sıfıra bölmek bir nan ise -2'nin kare köküne veya -3'ün kare köküne eşdeğerdir?

Nan, ek istisnalar getirmeden tamamlanması için geçersiz bir yanıt döndüren bir adım içeren bir hesaplamaya izin verir. Cevabın değer olduğunu doğrulamak için sadece Float.isNan () o eşdeğeri ile nandness (bu çanta değilse ben kelime) test edin.


3
Eğer outsideiolbut'un ne olduğunu gerçekten biliyorsam :-) hariçysegogut olarak düşünmek daha kolay olurdu.
paxdiablo

2

Ekleyeceğim

float i = Float.NaN;

Hem de

double i = Double.NaN;

Bu tür soruların ortak bir hilesi, ben bir int olduğunu varsayalım. Diğer yaygın varsayımlar s olabilir bir dize, x, y bir çift, ch bir char, b bir bayt vs.

Benzer bir soru; Bu asla dönmez, 'x' nedir

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

Oldukça sevdiğim bir başka soru; Bu döngü sonsuz bir döngüdür, x'in olası değerleri nelerdir. (: On ikisini sayıyorum :)

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

0

Bunun bir Java sorusu olduğunu biliyorum, ancak diğer diller için soruyu düşünmek ilgi çekicidir.

C'de, 'i' geçici bir tür 'evren soğumadan önce sonlanabilir' davranışı 'i' değişken olarak bildirilirse (böylece derleyici her bir yineleme için iki 'i' okuması yapmaya zorlanacaktır) ve eğer 'i' aslında başka bir şeyin onu etkileyebileceği bellekte olsaydı. Sonra tek bir yinelemenin iki okuması arasında 'i' değiştiğinde döngü sonlanır. ( Eklendi : olası bir yer - 'i' nin aslında bir G / Ç bağlantı noktasının adresinde, belki de bir konum sensörüne bağlı olduğu bir mikro bilgisayarda. 'İ' bir işaretçi değişkeni olsaydı daha mantıklı olurdu ( geçici belleğe bir işaretçi) ve ifade ' while (*i == *i);' idi.)

Diğer cevapların kanıtladığı gibi, C ++ 'da, kullanıcı tarafından tanımlanmış bir sınıftaysa, kullanıcı tarafından' == 'operatörü sağlanabilir, bu nedenle her şey mümkün olabilir.

Bunun yerine, NaN gibi, SQL tabanlı bir dilde, i değeri NULL olsaydı döngü sonsuz olmazdı; ancak, NULL olmayan herhangi bir değer döngüyü sonsuz yapar. Bu, Java'ya benzer, herhangi bir sayı (NaN yerine) döngüyü sonsuz yapar.

Yapının pratik bir kullanımı olduğunu görmüyorum, ancak ilginç bir trivia sorusu.


0

Bu çözümü görmekten şaşırdım:

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

Bir yoruma yanıt olarak şunu çalıştırmayı deneyin:

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

x teoride her zaman arksine (sin (x)) eşit olmalıdır, fakat pratikte değildir.


3
Neden olmasın? Tam olarak aynı veriler üzerinde tam olarak aynı hesaplamayı yapıyorsunuz, her iki sonuç da tamamen aynı hatayı içerecektir.
Loren Pechtel

Tam olarak nerede okuduğumu hatırlayamıyorum, ancak makinenize / uygulamanıza bağlı olarak, bir işlev çağrısındaki günah (x) farklı bir çağrının günahını (x) eşitleme şansına sahiptir. Kayan nokta basamaklarının doğruluğu ile ilgilidir (trig fonksiyonları hakkında özel bir şey, aynı değeri iki kez döndürmemelerini sağlar).
jkeys

Güncellememe bakın. Arcsine x'in günahını "geri alır", bu yüzden eşit olmalılar, ama değiller.
jkeys

Bu aynı şey değil. Loren'in dediği gibi, tam olarak aynı işlemi yapıyorsunuz x, bu da aynı sonucu aynı yanlışlık ile vermelidir. Arcsin, kayan nokta sayıları olan bir günahın sonucunu tersine çeviremez çünkü geçilen değer asin()tam olarak doğru olmayacaktır. Bu nedenle, sonucu asin()yanlış olacak, yanlış yapacaktır x == asin(sin(x)). Ayrıca, arcsin mutlaka bir günah işlemini "geri almaz" - sin işlevi x'in birden çok değeri için aynı sonucu verebilir, bu yüzden asin()sadece -π / 2 ve π / 2 arasındaki sayıları döndürür.
hbw

2
Başka bir deyişle, arcsin her zaman sin fonksiyonunu "geri alamaz" çünkü arcsin'in orijinal açının ne olduğunu bilmesi imkansızdır. Örneğin, hem π / 2 hem de 5π / 2'nin günahı 1 verir. Peki arcsin (1) nedir? Açıkçası ikisini de geri veremez, değil mi? Bu nedenle, arcsin sonucu bir dizi 2ians radyan ile sınırlandırılmalıdır, yani orijinal açı 0 ile 2 between arasında değilse veya C'nin durumunda, -π / 2 ve π / 2. (Gerçekten de, arcsin (sin (5π / 2)) = π / 2.) Her neyse, bu gerçekten uzun bir açıklama, ama umarım bu yanlış anlamaları gidermeye yardımcı olur.
hbw

0

Sonsuz döngü değil, bir iplik :)

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 == iatomik değildir. Böyle bir program tarafından kanıtlanmıştır:

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);
}

Güncelleme Burada sonsuz olmayan döngüye bir örnek daha verilmiştir (yeni evre oluşturulmamıştır).

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 Bir iş parçacığı kullanarak bir Java programı yazma imkanı olmadığı gerçeğine söyledikleriniz :), bu nedenle diğer tüm çözümler en az iki iş parçacığı kullanır ('Güncelleme' bölümündeki ikinci programımla tamamen aynıdır).
Andrey

Döngüyü frenlemiyor. Sonra herhangi bir kod while (i == i);yürütmek olmaz.
aalku

Finalize başka bir iş parçacığı kullanır, ancak belirtmek iyi bir şeydir. Bu orijinal sorunun "ve program sadece bir iş parçacığı kullanır" dedi nedeni .. Açıkça bunun açık bir cevap olduğunu belirtmek ve onlar daha fazla bakmak istiyorlar.
Bill K
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.