Javaでは、NaNはどういう意味ですか?


107

double希望の数まで縮小しようとするプログラムがあります。私が得る出力はNaNです。

NaNJavaで何を意味しますか?


NaNのとJavaでのNaNを使用して一般的な落とし穴の良い説明があります:ppkwok.blogspot.co.uk/2012/11/...は
フィル・

「NaNは何がいいのか?」Java(またはその他の言語)では、非常に便利なユースケースを提供できます。浮動小数点数の2次元配列がありますが、この2次元配列の一部に対して計算に意味のある値がない場合、その値を「NaN」で埋めます。これは、(この値がラスターイメージに変換されたときなど)私の計算の下流のユーザーに「この時点での値に注意を払わない」ことを知らせるために使用できます。非常に便利!
Dan H

ところで、正確には、ダブルを「縮小」するという意味ですか?好奇心が強い...
Dan H

回答:


153

このページからの引用:

「NaN」は「数ではない」を意味します。"Nan"は、浮動小数点演算にいくつかの入力パラメーターがあり、その演算によって未定義の結果が生成される場合に生成されます。たとえば、0.0を0.0で割ると、算術的に未定義になります。負の数の平方根を取ることも未定義です。


16
さらに、NaNは、浮動小数点演算のIEEE標準(IEEE 754)によって、Javaが盲目的に従う非常に明示的に定義されています。標準を読むと、多くのことに目が開かれます。ゼロという複数の値は、その1つです。
Esko、2010

37
また、NaN比較するとそれ自体とは異なる唯一の「数」であるという興味深い特性があります。したがって、一般的(及び多くの言語でのみ)試験番号があればxであるNaN以下の通りである:boolean isNaN(x){return x != x;}
quazgar

3
答えのリンクは死んでいますか?
2013

3
...「負の数の平方根をとることは(算術的に)未定義です」...それはそうではありません!その実際にi、それに非常によくPythonの取引のようないくつかの言語...それはではそうではないかもしれjava
ラファエル・T

5
@RafaelT複雑でない演算では未定義だと思います。Javaでは、floatまたはdoubleに複素数を割り当てる方法はありません。Pythonは動的に型付けされるため、この場合は単に複素数を返す可能性があります。
2014年

19

NaN「非数」を意味し基本的にはIEE 754浮動小数点規格の特別な浮動小数点値を表しています。NaNは通常、値が有効な浮動小数点数では表現できないものであることを意味します。

変換される値が別のものである場合、たとえば数値を表さない文字列を変換する場合、変換はこの値になります。


変換方法は?parseFloat()parseDouble?または、他の何か?
アロンソデルアルテ

14

NaN「非数」を意味し、たとえばゼロをゼロで除算するなど、浮動小数点数に対する未定義の演算の結果です。(ゼロ以外の数値をゼロで除算することも数学では通常未定義ですが、NaNではなく正または負の無限大になることに注意してください)。


5

NaN「数字ではない」という意味です。これは特別な浮動小数点値であり、演算の結果が定義されていないか、実数として表現できないことを意味します。

この値の詳細については、こちらをご覧ください。




4

数字ではないことを意味します。これは、多くのプログラミング言語で不可能な数値の一般的な表現です。


4

最小限の実行可能な例

まず知っておくべきことは、NaNの概念がCPUハードウェアに直接実装されていることです。

最近の主要なCPUはすべて、浮動小数点形式を指定するIEEE 754に準拠しているようで、NaNは特別な浮動小数点値であり、その規格の一部です。

したがって、この概念は、浮動小数点コードを直接CPUに出力するJavaを含め、どの言語でも非常によく似ています。

先に進む前に、私が書いた次の回答を最初に読んでおくとよいでしょう。

次に、Javaアクションについて説明します。コア言語にない関心のある関数のほとんどは内部にありjava.lang.Floatます。

Nan.java

import java.lang.Float;
import java.lang.Math;

public class Nan {
    public static void main(String[] args) {
        // Generate some NaNs.
        float nan            = Float.NaN;
        float zero_div_zero  = 0.0f / 0.0f;
        float sqrt_negative  = (float)Math.sqrt(-1.0);
        float log_negative   = (float)Math.log(-1.0);
        float inf_minus_inf  = Float.POSITIVE_INFINITY - Float.POSITIVE_INFINITY;
        float inf_times_zero = Float.POSITIVE_INFINITY * 0.0f;
        float quiet_nan1     = Float.intBitsToFloat(0x7fc00001);
        float quiet_nan2     = Float.intBitsToFloat(0x7fc00002);
        float signaling_nan1 = Float.intBitsToFloat(0x7fa00001);
        float signaling_nan2 = Float.intBitsToFloat(0x7fa00002);
        float nan_minus      = -nan;

        // Generate some infinities.
        float positive_inf   = Float.POSITIVE_INFINITY;
        float negative_inf   = Float.NEGATIVE_INFINITY;
        float one_div_zero   = 1.0f / 0.0f;
        float log_zero       = (float)Math.log(0.0);

        // Double check that they are actually NaNs.
        assert  Float.isNaN(nan);
        assert  Float.isNaN(zero_div_zero);
        assert  Float.isNaN(sqrt_negative);
        assert  Float.isNaN(inf_minus_inf);
        assert  Float.isNaN(inf_times_zero);
        assert  Float.isNaN(quiet_nan1);
        assert  Float.isNaN(quiet_nan2);
        assert  Float.isNaN(signaling_nan1);
        assert  Float.isNaN(signaling_nan2);
        assert  Float.isNaN(nan_minus);
        assert  Float.isNaN(log_negative);

        // Double check that they are infinities.
        assert  Float.isInfinite(positive_inf);
        assert  Float.isInfinite(negative_inf);
        assert !Float.isNaN(positive_inf);
        assert !Float.isNaN(negative_inf);
        assert one_div_zero == positive_inf;
        assert log_zero == negative_inf;
            // Double check infinities.

        // See what they look like.
        System.out.printf("nan            0x%08x %f\n", Float.floatToRawIntBits(nan           ), nan           );
        System.out.printf("zero_div_zero  0x%08x %f\n", Float.floatToRawIntBits(zero_div_zero ), zero_div_zero );
        System.out.printf("sqrt_negative  0x%08x %f\n", Float.floatToRawIntBits(sqrt_negative ), sqrt_negative );
        System.out.printf("log_negative   0x%08x %f\n", Float.floatToRawIntBits(log_negative  ), log_negative  );
        System.out.printf("inf_minus_inf  0x%08x %f\n", Float.floatToRawIntBits(inf_minus_inf ), inf_minus_inf );
        System.out.printf("inf_times_zero 0x%08x %f\n", Float.floatToRawIntBits(inf_times_zero), inf_times_zero);
        System.out.printf("quiet_nan1     0x%08x %f\n", Float.floatToRawIntBits(quiet_nan1    ), quiet_nan1    );
        System.out.printf("quiet_nan2     0x%08x %f\n", Float.floatToRawIntBits(quiet_nan2    ), quiet_nan2    );
        System.out.printf("signaling_nan1 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan1), signaling_nan1);
        System.out.printf("signaling_nan2 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan2), signaling_nan2);
        System.out.printf("nan_minus      0x%08x %f\n", Float.floatToRawIntBits(nan_minus     ), nan_minus     );
        System.out.printf("positive_inf   0x%08x %f\n", Float.floatToRawIntBits(positive_inf  ), positive_inf  );
        System.out.printf("negative_inf   0x%08x %f\n", Float.floatToRawIntBits(negative_inf  ), negative_inf  );
        System.out.printf("one_div_zero   0x%08x %f\n", Float.floatToRawIntBits(one_div_zero  ), one_div_zero  );
        System.out.printf("log_zero       0x%08x %f\n", Float.floatToRawIntBits(log_zero      ), log_zero      );

        // NaN comparisons always fail.
        // Therefore, all tests that we will do afterwards will be just isNaN.
        assert !(1.0f < nan);
        assert !(1.0f == nan);
        assert !(1.0f > nan);
        assert !(nan == nan);

        // NaN propagate through most operations.
        assert Float.isNaN(nan + 1.0f);
        assert Float.isNaN(1.0f + nan);
        assert Float.isNaN(nan + nan);
        assert Float.isNaN(nan / 1.0f);
        assert Float.isNaN(1.0f / nan);
        assert Float.isNaN((float)Math.sqrt((double)nan));
    }
}

GitHubアップストリーム

次で実行:

javac Nan.java && java -ea Nan

出力:

nan            0x7fc00000 NaN
zero_div_zero  0x7fc00000 NaN
sqrt_negative  0xffc00000 NaN
log_negative   0xffc00000 NaN
inf_minus_inf  0x7fc00000 NaN
inf_times_zero 0x7fc00000 NaN
quiet_nan1     0x7fc00001 NaN
quiet_nan2     0x7fc00002 NaN
signaling_nan1 0x7fa00001 NaN
signaling_nan2 0x7fa00002 NaN
nan_minus      0xffc00000 NaN
positive_inf   0x7f800000 Infinity
negative_inf   0xff800000 -Infinity
one_div_zero   0x7f800000 Infinity
log_zero       0xff800000 -Infinity

したがって、これからいくつかのことを学びます。

  • 賢明な結果を持たない奇妙な浮動演算は、NaNを与えます。

    • 0.0f / 0.0f
    • sqrt(-1.0f)
    • log(-1.0f)

    を生成しNaNます。

    Cにおいて、要求信号がこのような操作に上昇させるためには、実際に可能でありfeenableexcept、それらを検出するために、私はそれをJavaで露出しているとは思わない:ゼロ1/0所与のエラーが、浮動小数点除算整数ない理由の1 / 0.0 「Inf」を返しますか?

  • プラスまたはマイナスの無限大の限界にある奇妙な演算は、NaNの代わりに+-無限大を与えます

    • 1.0f / 0.0f
    • log(0.0f)

    0.0 ほぼこのカテゴリに分類されますが、問題はおそらくそれがプラスまたはマイナスの無限大に進む可能性があるため、NaNとして残されました。

  • NaNが浮動小数点演算の入力である場合、出力もNaNになる傾向があります

  • NaN 0x7fc000000x7fc000010x7fc00002、いくつかの可能な値があります0x7fc00000。ただし、x86_64は生成するだけのようです。

  • NaNと無限大は同様のバイナリ表現を持っています。

    それらのいくつかを分解してみましょう:

    nan          = 0x7fc00000 = 0 11111111 10000000000000000000000
    positive_inf = 0x7f800000 = 0 11111111 00000000000000000000000
    negative_inf = 0xff800000 = 1 11111111 00000000000000000000000
                                | |        |
                                | |        mantissa
                                | exponent
                                |
                                sign
    

    これから、IEEE754が指定していることを確認します。

    • NaNと無限大の両方の指数== 255(すべて1)
    • 無限大には仮数== 0があります。したがって、可能な無限は2つだけです:+と-、符号ビットで区別
    • NaNには仮数!= 0があります。したがって、無限大である仮数== 0を除いて、いくつかの可能性があります。
  • NaNは正または負(最上位ビット)のいずれかですが、これは通常の操作には影響しません

Ubuntu 18.10 amd64、OpenJDK 1.8.0_191でテスト済み。


3

Javaの男ではありませんが、JSや他の言語では、「Not a Number」を使用しています。つまり、何らかの操作によって有効な数値ではなくなりました。



3

有効な浮動小数点値ではありません(たとえば、ゼロによる除算の結果)

http://en.wikipedia.org/wiki/NaN


私はこの答えを誤解します。まず、「NaN」はIEEE floatの有効な値です。(結局のところ、それは仕様で定義されています...その「有効」ですよね?)第二に、「ゼロによる除算」は、IEEE「正の無限大」または「負の無限大」で表すことができます。他のいくつかの答えが正しく指摘しているように、「NaN」のより良い例は「ゼロをゼロで割ったもの」です。
Dan H

「有効な値」と「仕様で定義」は同じものではありません。0/0に同意しました。
Vladimir Dyuzhev 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.