John Squirrels
レベル 41
San Francisco

JavaのNaN

ランダム グループに公開済み
Java では、「NaN」は「Not a Number」を表します。これは例外の一種ではなく、驚くべきことに、NaN のデータ型も数値です。しかし、多くの場合、初心者プログラマーが意図せずにそれを取得し、さらにそれを計算に使用してしまいます。したがって、Java で互換性のないデータ型を一緒に使用すると、スロー可能なエラーが発生する可能性があります。java.lang.ArithmeticException: / by zeroNaN と同じとみなされることもよく見られます。ただし、Java では両方を異なる方法で扱います。十分に不可解ですか?包括的な理解を得るために、これらが互いにどのように異なるのかを詳しく説明します。この記事を最後まで読むと、非数値 (nan) を生成する可能性のある操作と、それを処理するいくつかの簡単な方法について学びます。

NaNとは何ですか?

では、NaN とは何でしょうか? 多くの人が想像しているように、「NaN」は Java で「非数」を表すために使用されます。これは、オーバーフローとエラーを示す特別な浮動小数点値です。これは、浮動小数点数がゼロで除算されるとき、または負の数の平方根が計算されるときに生成されます。Java の NaN - 1たとえば、次のスニペットを見てください。

public class NaN
{
    public static void main(String[]args)
    {
        System.out.println(0.0 / 0.0);	  //zero divided by zero
        System.out.println(Math.sqrt(-1)); //take sqrt of negative number
        System.out.println(10.0 % 0);      //taking mod by zero	
    }
}
出力

NaN                                                                                                                                           
NaN                                                                                                                                           
NaN
上のスニペットでは、3 つの単純な操作の結果として NaN が生成されることがわかります。
  • ゼロをゼロで割るfloat / double
  • 負の数の根元を取得します (Math.sqrt(-x))。数学では、負の数の平方根を取ると虚数が得られます。このケースは、Java で NaN を返すことで処理されます。
  • 数値をゼロで割ると、値をゼロで割った余りが返されます。したがって、NaN が返されます。

NaN は正の無限大や負の無限大とどう違うのでしょうか?

IEEE 754 仕様によれば、境界ケースを処理するための 3 つの特別な浮動小数点値と double 値があります。
  • 正の無限大
  • 負の無限大
  • NaN
正の数を 0 で割った結果は、正の無限大になります。同様に、負の無限大は、負の数をゼロで除算した結果として得られます。すべての浮動小数点値はデータ型 double にも適用できることに注意してください。float の制限された精度では十分ではない場合があります。ただし、NaN が float と double の両方でどのように機能するかについては、後のセクションで説明します。

NaN()メソッドとは何ですか?

isNaN()これは、NaN 値かどうかを確認するための Java の基本的なメソッドの 1 つです。上で 3 つのケースについて説明したように、 isNaN() メソッドが+infinity-infinity 、および NaN 値をどのように区別するかをテストします。

public class isNaN
{ public static void main(String[]args)
  { 
    Double posInfinity = +2.0 / 0.0;
    Double negInfinity = -3.5 / 0.0;
    Double nanVal = 50 % 0.0;


    System.out.println ("+" + posInfinity + ".IsNaN() = " + posInfinity.isNaN());
    System.out.println ( negInfinity + ".IsNaN() = " + negInfinity.isNaN());
    System.out.println ( nanVal +  ".IsNaN() = " + nanVal.isNaN());
  }
}
出力

+Infinity.IsNaN() = false                                                                                                                       
-Infinity.IsNaN() = false                                                                                                                       
NaN.IsNaN() = true

NaN 値を比較するにはどうすればよいですか?

すべての NaN 値は別個のものとみなされます。これは、単一の NaN が他の NaN と等しくないことを意味します。この原則により、ある値を別の値と比較すると、結果は常に負になります。NaN は順序付けされていないため、たとえ単一の NaN を含む数値比較でも false を返します。Java では、比較を実行するために、両方のクラスの定数フィールドに Float.NaN と Double.NaN が提供されています。これらは 2 つの別々のシナリオで区別できます。
  • True: 不等号 (!=) の場合のみ
  • False: すべての比較オペランド (==、<=、>=、<、>)
以下に実際の例を示します。

public class ComparingNaN
{ public static void main(String[] args)                                                                                                     
  {
    // Comparing NaN values for Float constants
    System.out.println (Float.NaN != Float.NaN); // true
    System.out.println (Float.NaN == Float.NaN); // false
    System.out.println (Float.NaN < Float.NaN);  // false
    System.out.println (Float.NaN > Float.NaN);  // false
    System.out.println (Float.NaN <= Float.NaN); // false
    System.out.println (Float.NaN >= Float.NaN); // false

    // Comparing NaN values for Float constants
    System.out.println (Double.NaN != Double.NaN); // true
    System.out.println (Double.NaN == Double.NaN); // false
    System.out.println (Double.NaN < Double.NaN);  // false
    System.out.println (Double.NaN > Double.NaN);  // false
    System.out.println (Double.NaN <= Double.NaN); // false
    System.out.println (Double.NaN >= Double.NaN); // false
  }
}

NaN 値を生成するにはどうすればよいですか?

最後に、Not a Number (nan) を取得する一般的な例をいくつか見てみましょう。

public class GenerateNaNValues {  
  static final float ZERO = 0;
  public static void main (String[]args)
  {
    System.out.println("ZERO / ZERO = " + (ZERO / ZERO));
    System.out.println("+INFINITY - INFINITY = " + 
    (Float.POSITIVE_INFINITY + Float.NEGATIVE_INFINITY));
    System.out.println("-INFINITY * ZERO = " + (Float.NEGATIVE_INFINITY * ZERO));
    System.out.println("+INFINITY * ZERO = " + (Float.POSITIVE_INFINITY * ZERO));
    System.out.println("log10(-10) = " +  Math.log(-10));
    System.out.println("√-10 = " + Math.sqrt(-10));
    System.out.println("NaN + 10 = " + (Float.NaN + 10));
    System.out.println("NaN - 10 = " + (Float.NaN - 10));
    System.out.println("NaN * 10 = " + (Float.NaN * 10));
    System.out.println("NaN / 10 = " + (Float.NaN / 10));
    System.out.println("NaN + NaN = " + (Float.NaN + Float.NaN));
    System.out.println("NaN - NaN = " + (Float.NaN - Float.NaN));
    System.out.println("NaN * NaN = " + (Float.NaN * Float.NaN));
    System.out.println("NaN / NaN = " + (Float.NaN / Float.NaN));
  }
}
出力:

ZERO / ZERO = NaN                                                                                                                               
+INFINITY - INFINITY = NaN                                                                                                                      
-INFINITY * ZERO = NaN                                                                                                                          
+INFINITY * ZERO = NaN                                                                                                                          
log10(-10) = NaN                                                                                                                                
√-10 = NaN                                                                                                                                      
NaN + 10 = NaN                                                                                                                                    
NaN - 10 = NaN                                                                                                                                  
NaN * 10 = NaN                                                                                                                                  
NaN / 10 = NaN                                                                                                                                  
NaN + NaN = NaN                                                                                                                                 
NaN - NaN = NaN                                                                                                                                 
NaN * NaN = NaN                                                                                                                                 
NaN / NaN = NaN

結論

NaN を生成する多数の操作を見てきたので、NaN については十分に理解できたはずです。最初は戸惑うかもしれませんが、これに対処するのに複雑なことは何もありません。倍精度/浮動小数点計算で値が NaN でないかどうかをチェックする少しの習慣を身につけることで、多くの手間を省くことができます。最初は忘れても全然大丈夫です。軽微なトラブルシューティングについては、いつでもこの記事を参照してください。コンパイル可能でエラーのないコードを一度に作成するには、長年の経験が必要です。それでは、実際にコードを作成して、素晴らしいものを構築してみましょう。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION