「ながら(i == i);」シングルスレッドアプリケーションで非無限ループになりますか?


141

答えられない質問が出てきました。

Javaに次のループ定義があるとします。

while (i == i) ;

ループが無限ループではなく、プログラムが1つのスレッドのみを使用している場合のタイプiと値は何ですか?i


7
ああ、神の為に、人々はなぜ彼らが反対票を投じるのかについてコメントする名誉がありますか?これはなぞなぞとしてタグ付けされています、何が問題なのですか?
user54579 2009年

10
何に対しても反対投票をやめられない人もいると思います。
FerranB 2009年

1
これを引き起こしてすみません:/私は本当に答えがほしかったので、自分で解決することはできませんでした。
Zizzencs、2009年

1
@nickolai、それがSOの性質です-ドライブバイダウン投票は残念ながら現実であり、コメントを要求するという考えは議論され拒否されました。しかし、結局のところ、「コミュニティ」はこの質問に賛成しているようです。
paxdiablo 2009年

1
この種の質問のトリックの1つは、人々が特定の変数名のタイプを想定することです。つまり、iはint、dはdouble、sは文字列またはshort、chはchar、lはlong、b forバイトまたはブール。どのタイプが提案され、それが何であるかを自問する必要があります。
Peter Lawrey、

回答:


125
double i = Double.NaN;

Double.equals()のAPI は、「Double.NaN == Double.NaNの値はfalseです」という答えを示しています。これは、Java言語仕様の「浮動小数点型、形式、および値」で詳しく説明されています。

NaN数値比較演算子に、順不同で<<=>、および>= リターンfalseの一方または両方のオペランドがある場合NaN。等号演算子==false、いずれかのオペランドがの場合に戻りNaN、不等式演算子!=true、いずれかのオペランドがの場合に戻りますNaN具体的には、x!=xあるtrue場合に限りx、ISNaN、及び(x<y) == !(x>=y)あろうfalse場合x、またはyありますNaN


1
ああ、そうすれば「数字ではない」ことができる!
Filip Ekberg、

12
その数学的に確かな理由は、なぜある非実数が別の数値と等しくなければならないのですか?5/0!= sqrt(-4)
ゴードングスタフソン

2
@CrazyJugglerDrummer:多分、しかし同様にx == x常に真実であるべきです。なぜ何かがそれ自体と等しくないはずですか?
Bart van Heukelom、2011

1
バート:本当に、未知は必ずしも未知と等しいとは限らないからです。時にはそれが...データベースにはNULLを持っている理由です、便利です
Konerak

2
@inovaovao:いいえ、DBではnull=nullnullです。NULL IS NULL1です
。– Konerak

29

の値iは無効になります。「番号ではない」。

グーグルで調べたところ、JavaでNaN(非数)を使用できることがわかりました。したがって、浮動小数点数はデータ型であり、値はNaNです。こちらをご覧ください


12
はい、それだけです。iの値はJon Skeetです。
Andrew Rollings、

私は通常、理由もなく反対票を投じる人々を憎みます...私は最初に「数字ではない」と言いましたが、Javaがそれを処理できるとは思いませんでした。
Filip Ekberg、



8

確かではありませんが、(i == i)はマルチスレッドプロセスのアトミック操作ではないので、ループを実行しているスレッドにスタックするために、その値のプッシュの間に他のスレッドによってi値が変更される場合、その条件は偽りであること。


8

他の人がそれがNaNであると言ったので、の公式(JDK 6)実装に興味を持ちました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である場合、それは-2の平方根または-3の平方根に相当しますか?

ナンは、余分な例外を導入することなく、無効な回答を返すステップを含む計算を完了することを許可します。答えが値であることを確認するには、同等のFloat.isNan()を介して単純に非ナンド(つまり、それをバッグしない場合はその単語)をテストします。


3
私がexceptiolbutが何であるかを実際に知っていれば、それをexceptiolbutと考える方が簡単でしょう:-)。
paxdiablo 2009年

2

追加します

float i = Float.NaN;

と同様

double i = Double.NaN;

これらの種類の質問での一般的なトリックは、私がintであると仮定した場合です。その他の一般的な仮定として、sは文字列、x、yは倍精度、chは文字、bはバイトなどがあります。このような質問が表示された場合は、「i」が期待値タイプではないことに疑いの余地があります。

同様の質問です。これは決してループしない、「x」とは

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

私がかなり気に入っているもう1つの質問は、このループは無限ループです。xの可能な値は何ですか。(:私はそれらの12を数えます:)

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

0

私はこれがJavaの質問であることを知っていますが、他の言語の質問を検討することは興味深いものです。

Cでは、「i」が揮発性として宣言されている場合、「int」などの単純な型は「宇宙が冷える前に終了する」動作を示す可能性があります(そのため、コンパイラは反復ごとに「i」の2回の読み取りを強制されます)そして、「i」が実際にメモリにあり、他の何かがそれに影響を与える可能性がある場合。その後、1回の反復の2つの読み取り間で「i」が変更されると、ループが終了します。(追加:可能な場所-'i'が実際にはI / Oポートのアドレスに配置されているマイクロコンピューター内で、おそらく位置センサーに接続されています。'i 'がポインター変数である場合、よりもっともらしくなります(揮発性メモリへのポインタ)およびステートメントは ' while (*i == *i);'でした。)

他の回答からもわかるように、C ++では、iがユーザー定義クラスの場合、ユーザーは '=='演算子を指定できるため、何でも可能です。

NaNのように、SQLベースの言語では、iの値がNULLの場合、ループは無限ではありません。ただし、NULL以外の値を指定すると、ループが無限になります。これはむしろJavaに似ており、(NaNとは対照的に)任意の数でループが無限になります。

私はこの構成が実際に使用されているとは思いませんが、興味深いトリビアの質問です。


0

私はこの解決策を見ていないことに驚きました:

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

コメントに応じて、これを実行してみてください:

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

xは常に理論的にはアークサイン(sin(x))と等しくなければなりませんが、実際には等しくありません。


3
何故なの?まったく同じデータに対してまったく同じ計算を行っているため、両方の結果にまったく同じエラーが含まれます。
Loren Pechtel 2009

どこで読んだか正確に思い出せませんが、マシン/実装によっては、ある関数呼び出しのsin(x)が、別の呼び出しのsin(x)と等しくなる可能性が非常に低くなります。これは、浮動小数点の桁数の精度に関係しています(トリガー関数について、何かが同じ値を2度返さないようにする特別な点があります)。
jkeys 2009

私のアップデートを見てください。Arcsineはxの罪を「取り消す」ため、等しいはずですが、等しくありません。
jkeys 2009

それは同じことではありません。ローレンが言ったように、あなたはでまったく同じ操作を実行しています。xこれはまったく同じ不正確さでまったく同じ結果をもたらすはずです。渡された値asin()が正確ではないため、Arcsinは浮動小数点数を含むsinの結果を元に戻すことができません。したがって、の結果はasin()不正確になり、誤りになりx == asin(sin(x))ます。また、arcsinは必ずしもsin操作を「取り消す」とは限りません。sin関数は、xの複数の値に対して同じ結果をasin()返す可能性があるため、-π/ 2とπ/ 2の間の数値のみを返します。
hbw 2009

2
言い換えると、arcsinは元の角度が何であるかを知ることができないため、arcsinは常にsin関数を「取り消す」ことができない。たとえば、π/ 2と5π/ 2の両方の罪は1を与えます。しかし、arcsin(1)とは何ですか?明らかに両方を返すことはできませんよね?したがって、arcsinの結果は2πラジアンの範囲に制限する必要があります。つまり、元の角度が0と2πの間、またはCの場合-π/ 2とπ/ 2。(確かに、arcsin(sin(5π/ 2))=π/ 2。)とにかく、それは非常に長い説明でしたが、誤解を解消するのに役立つことを願っています。
hbw 2009

0

無限ループではなく、1つのスレッド:)

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 == iアトミックではありません。そのようなプログラムによって証明された:

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

更新 これは、無限ループではないもう1つの例です(新しいスレッドは作成されません)。

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 1つのスレッドを使用してJavaプログラムを作成する可能性がないという事実に対するあなたの意見:)したがって、他のすべてのソリューションは少なくとも2つのスレッドを使用します(「更新」セクションの2番目のプログラムとまったく同じです)。
アンドレイ

それはループにブレーキをかけていません。その後のコードはwhile (i == i);実行されません。
aalku

Finalizeは別のスレッドを使用しますが、指摘するのは良いことです。これが、元の質問が「プログラムは1つのスレッドしか使用しない」と言った理由です。これは明白な答えであり、さらに調査することを望んでいると明確に述べています。
ビルK
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.