1. 概要

簡単に言うと、 NaN は、「数値ではない」を表す数値データ型の値です。

このクイックチュートリアルでは、Javaの NaN 値と、この値を生成または含むことができるさまざまな操作について説明します。

2. NaN とは何ですか?

NaNは通常、無効な演算の結果を示します。たとえば、ゼロをゼロで除算しようとすることは、そのような演算の1つです。

表現できない値にもNaNを使用します。値( i )は複素数でしか記述できないため、-1の平方根はそのようなケースの1つです。

浮動小数点演算のIEEE標準(IEEE 754)は、NaN値を定義します。 Javaでは、浮動小数点型はfloatであり、この標準をdouble実装します。

Javaは、floatタイプとdoubleタイプの両方のNaN定数をFloat.NaNおよびDouble.NaNとして定義します。

「「 double型のNot-a-Number(NaN)値を保持する定数。 これは、Double.longBitsToDouble(0x7ff8000000000000L)によって返される値と同等です。」

と:

「float型のNot-a-Number(NaN)値を保持する定数。 これは、Float.intBitsToFloat(0x7fc00000)によって返される値と同等です。」

Javaの他の数値データ型には、このタイプの定数はありません。

3. NaNとの比較

Javaでメソッドを記述している間、入力が有効であり、期待される範囲内にあることを確認する必要があります。 NaN 値は、ほとんどの場合、有効な入力ではありません。 したがって、入力値が NaN 値ではないことを確認し、これらの入力値を適切に処理する必要があります。

NaNはフローティングタイプの値と比較できません。 これは、 NaNを含むすべての比較操作でfalse を取得することを意味します( true を取得する「!=」を除く)。

xNaN:である場合に限り、「 x!=x」に対してtrueを取得します。

System.out.println("NaN == 1 = " + (NAN == 1));
System.out.println("NaN > 1 = " + (NAN > 1));
System.out.println("NaN < 1 = " + (NAN < 1));
System.out.println("NaN != 1 = " + (NAN != 1));
System.out.println("NaN == NaN = " + (NAN == NAN));
System.out.println("NaN > NaN = " + (NAN > NAN));
System.out.println("NaN < NaN = " + (NAN < NAN));
System.out.println("NaN != NaN = " + (NAN != NAN));

上記のコードを実行した結果を見てみましょう。

NaN == 1 = false
NaN > 1 = false
NaN < 1 = false
NaN != 1 = true
NaN == NaN = false
NaN > NaN = false
NaN < NaN = false
NaN != NaN = true

したがって、「==」または「!=」を使用してNaNと比較してNaNをチェックすることはできません。実際、floatで「==」または「!=」演算子を使用することはめったにありません。 またはdoubleタイプ。

代わりに、「 バツ ! = x” 。 この式は、次の場合にのみtrueを返します。 ナン。

メソッドを使用することもできます Float.isNaN Double.isNaN これらの値を確認するには 。 これは、より読みやすく理解しやすいため、推奨されるアプローチです。

double x = 1;
System.out.println(x + " is NaN = " + (x != x));
System.out.println(x + " is NaN = " + (Double.isNaN(x)));
        
x = Double.NaN;
System.out.println(x + " is NaN = " + (x != x));
System.out.println(x + " is NaN = " + (Double.isNaN(x)));

このコードを実行すると、次の結果が得られます。

1.0 is NaN = false
1.0 is NaN = false
NaN is NaN = true
NaN is NaN = true

4. NaNを生成する操作

floatおよびdoubleタイプを含む操作を行うときは、NaNの値に注意する必要があります。

一部の浮動小数点メソッドおよび操作は、例外をスローする代わりにNaN値を生成します。 そのような結果を明示的に処理する必要があるかもしれません。

数値以外の値になる一般的なケースは、数学的に定義されていない数値演算です。

double ZERO = 0;
System.out.println("ZERO / ZERO = " + (ZERO / ZERO));
System.out.println("INFINITY - INFINITY = " + 
  (Double.POSITIVE_INFINITY - Double.POSITIVE_INFINITY));
System.out.println("INFINITY * ZERO = " + (Double.POSITIVE_INFINITY * ZERO));

これらの例は、次の出力になります。

ZERO / ZERO = NaN
INFINITY - INFINITY = NaN
INFINITY * ZERO = NaN

実数の結果が得られない数値演算でも、 NaN:が生成されます。

System.out.println("SQUARE ROOT OF -1 = " + Math.sqrt(-1));
System.out.println("LOG OF -1 = " +  Math.log(-1));

これらのステートメントは次のようになります。

SQUARE ROOT OF -1 = NaN
LOG OF -1 = NaN

オペランドとしてNaNを使用するすべての数値演算は、結果としてNaNを生成します。

System.out.println("2 + NaN = " +  (2 + Double.NaN));
System.out.println("2 - NaN = " +  (2 - Double.NaN));
System.out.println("2 * NaN = " +  (2 * Double.NaN));
System.out.println("2 / NaN = " +  (2 / Double.NaN));

そして、上記の結果は次のとおりです。

2 + NaN = NaN
2 - NaN = NaN
2 * NaN = NaN
2 / NaN = NaN

最後に、nulldoubleまたはfloatタイプの変数に割り当てることはできません。 代わりに、 NaN をそのような変数に明示的に割り当てて、欠落している値または不明な値を示すことができます。

double maxValue = Double.NaN;

5. 結論

この記事では、NaNとそれに関連するさまざまな操作について説明しました。 また、Javaで浮動小数点計算を明示的に実行しながら、NaNを処理する必要性についても説明しました。

完全なソースコードは、GitHubにあります。