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 |
|
参考文献
|
[JLS 2015] |
|
| [Seacord 2015] |
翻訳元
これは以下のページを翻訳したものです。
NUM07-J. Do not attempt comparisons with NaN (revision 102)



