JPCERT コーディネーションセンター

NUM07-J. NaNとの比較を行わない

NUM07-J. NaNとの比較を行わない

『Java言語仕様』§4.2.3「浮動小数点数型とその形式、値」[JLS 2015] には以下のように規定されている。

NaN (not-a-number) は順序付けされない (unordered) ため、数値比較演算子<<=>>=は、オペランドのいずれかまたは両方がNaNである場合にfalseを返す。等値演算子==はいずれかのオペランドがNaNである場合にfalseを返し、非等値演算子!=はいずれかのオペランドがNaNである場合にtrueを返す。

NaNが順序付けされないというこの性質は、しばしばプログラマの想定外であるため、NaNとの直接の比較は行うべきでない。NaNのセマンティクスを考慮することなく浮動小数点数の比較を行うコードを書くと、問題が発生する可能性がある。たとえば、入力にNaN値が含まれることを考慮しないような入力値検査は予期せぬ結果をもたらす可能性がある (「NUM08-J. 浮動小数点数入力が例外値でないかを検査する」を参照)。

違反コード

以下の違反コードではNaNとの直接の比較を行っている。NaNのセマンティクスに従い、NaNとの比較はすべてfalseとなる (!=演算子だけは例外的にtrueを返す)。結果的に、この比較は常にfalseを返し、"result is NaN"メッセージが出力されることはない。

public class NaNComparison {
  public static void main(String[] args) {
    double x = 0.0;
    double result = Math.cos(1/x); // 入力が infinity のとき NaN を返す
    if (result == Double.NaN) { // 比較は常に false!
      System.out.println("result is NaN");
    }
  }
}
適合コード

以下のコードでは、Double.isNaN()メソッドを使用し、式がNaN値であるかどうかをチェックしている。

public class NaNComparison {
  public static void main(String[] args) {
    double x = 0.0;
    double result = Math.cos(1/x); // 入力が infinity のとき NaN を返す
    if (Double.isNaN(result)) {
      System.out.println("result is NaN");
    }
  }
}
リスク評価

NaN値との比較は予期せぬ結果をもたらす可能性がある。

ルール

深刻度

可能性

自動検出

自動修正

優先度

レベル

NUM07-J

P6

L2

自動検出

NaNとの比較を自動検出することは容易である。しかし、NaNが含まれている可能性まで考慮して計算結果が正しく処理されたかどうかを判断するのは一般に困難である。ヒューリスティックな検査は役に立つかもしれない。

ツール バージョン チェッカー 説明
Klocwork

2025.2

JAVA.COMPARE.NAN
Parasoft Jtest 2024.2 CERT.NUM07.NAN Avoid comparisons to Double.NaN or Float.NaN
PVS-Studio

7.38

V6038
参考文献

[FindBugs 2008]

FE: Doomed test for equality to NaN

[JLS 2015]

§4.2.3, "Floating-Point Types, Formats, and Values"

[Seacord 2015] Image result for video icon NUM07-J. Do not attempt comparisons with NaN LiveLesson
翻訳元

これは以下のページを翻訳したものです。

NUM07-J. Do not attempt comparisons with NaN (revision 102)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter