Java で、NaN や Infinity を int にキャストしたときの値

NaN や Infinity を int にキャストなんて普通はしないと思うのですが、やってみたらこうなりました。

  • (int)Double.NaN == 0
  • (int)Double.POSITIVE_INFINITY == Integer.MAX_VALUE
  • (int)Double.NEGATIVE_INIFINITY == Integer.MIN_VALUE
public static void main(String[] args) throws Exception {
    // NaN: 0
    System.out.println(
        Double.NaN + ": " + (int) Double.NaN);
    
    // Infinity: 2147483647
    System.out.println(
        Double.POSITIVE_INFINITY + ": " + (int) Double.POSITIVE_INFINITY);
    
    // -Infinity: -2147483648
    System.out.println(
        Double.NEGATIVE_INFINITY + ": " + (int) Double.NEGATIVE_INFINITY);
}

この挙動について、Java 言語仕様 第3版には以下のように書かれていました。

5.1.3 プリミティブ型のナローイング変換
浮動小数点から整数型 T へのナローイング変換は、以下の2ステップにて行われる:

  1. 第1のステップでは、浮動小数点数を以下に従って、T が long である場合は long へと、T が byte, short, char, int である場合は int へと変換する:
    • 浮動小数点数が NaN である場合、変換の第1ステップの結果は、int あるいは long のゼロとなる。
      そうでなく、浮動小数点が無限大でない場合、その浮動小数点をIEEE754規格によるゼロへの丸めモードによってゼロに向かった整数値 V へと丸める。その後、以下の2つの場合に分かれる:
      • T が long であり、この整数値が long で表現できる場合、第1ステップの結果は long 値の V となる。
      • そうでなく、この整数値が int で表現できる場合、第1ステップの結果は int 値の V となる。
    • そうでない場合は、以下のいずれかが真となるはずである:
      • 値が小さすぎる(大きな絶対値となる負の値や、負の無限大)場合、第1ステップの結果は int あるいは long 型で表現可能な最小値となる。
      • 値が大きすぎる(大きな絶対値となる性の値や、正の無限大)場合、第1ステップの結果は int あるいは long 型で表現可能な最大値となる。
  2. 第2のステップでは:
    • T が int あるいは long である場合、変換結果は第1ステップの結果となる。
    • T が byte, char, shrot である場合、変換結果は第1ステップの結果をT型にナローイング変換した結果となる。

たしかに、このような変換なら納得です。