NUM09-J. 浮動小数点数型変数をループカウンタとして使用しない
浮動小数点数型変数をループカウンタとして使用してはならない。精度に限界のあるIEEE 754浮動小数点数型は、次に示すように、すべての値を表現できるわけではない。
- 単純な有理数すべてを厳密に表現できるわけではない。
- すべての10進数を厳密に表現できるわけではない。10進数では少ない桁数で表現できる場合でも、2進数では正確に表現できないことがある。
- 大きな値のすべての桁を表現できるとは限らない。値の大きな浮動小数点数をインクリメントしたとしても、利用可能な精度の範囲では値は変わらないかもしれない。
このルールにおいて「ループカウンタ」とは、do、while、forループの制御式として使われる比較式のオペランドである帰納変数のことである。「帰納変数」とは、ループの繰り返しごとに一定量増減する変数のこと [Aho 1986] で、(ループ内で実行される関数の中ではなく) ループ本体で直接変更されるものを指す。
このルールは「NUM04-J. 正確な計算が必要なときは浮動小数点数を使わない」の一部である。
違反コード
以下の違反コード例では浮動小数点数型変数をループカウンタとして使用している。0.1という小数は、float型でもdouble型でも厳密に表現することはできない。
for (float x = 0.1f; x <= 1.0f; x += 0.1f) {
System.out.println(x);
}
0.1fはfloat型で表現できる近似値に丸められるため、繰り返し処理でxに加算される実際の値は0.1よりもわずかに大きい。それゆえ、ループは9回だけ実行され、期待とは異なる結果を出力する。
適合コード
以下の適合コードではint型整数をループカウンタとして使用しており、期待した浮動小数点数が得られる。
for (int count = 1; count <= 10; count += 1) {
float x = count/10.0f;
System.out.println(x);
}
違反コード
以下の違反コードでは、浮動小数点数型変数をループカウンタとして用いてインクリメントしているが、与えられた精度では値が小さすぎて変化しない。
for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) {
/* ... */
}
このコードは無限にループする。
適合コード
以下の適合コードではint型変数をループカウンタとして使用し、その値を元に浮動小数点数を算出している。またdouble型を使い、求める値を表現するために十分な精度が得られることを保証している。さらに、FP-strictモードで実行すると、結果の可搬性が保証される (詳しくは「NUM53-J. どのプラットフォームでも一貫した浮動小数点数演算を行うために strictfp 修飾子を使う」を参照)。
for (int count = 1; count <= 10; count += 1) {
double x = 100000000.0 + count;
/* ... */
}
リスク評価
ループカウンタに浮動小数点数を使用すると、プログラムの予期せぬ動作につながる恐れがある。
|
ルール |
深刻度 |
可能性 |
自動検出 |
自動修正 |
優先度 |
レベル |
|---|---|---|---|---|---|---|
|
NUM09-J |
低 |
中 |
可 |
不可 |
P4 |
L3 |
自動検出
浮動小数点数型ループカウンタの検出は容易である。
| ツール | バージョン | チェッカー | 説明 |
|---|---|---|---|
| Klocwork |
2025.2 |
JAVA.LOOP.CTR.FLOAT |
|
| Parasoft Jtest | 2024.2 | CERT.NUM09.FPLI | Do not use floating point variables as loop indices |
| PVS-Studio |
7.39 |
V6108 |
|
関連ガイドライン
| ISO/IEC TR 24772:2010 |
Floating-point Arithmetic [PLF] |
参考文献
| [Aho 1986] |
|
|
Puzzle 34, "Down for the Count" |
|
|
[JLS 2015] |
|
| [Seacord 2015] |
翻訳元
これは以下のページを翻訳したものです。
NUM09-J. Do not use floating-point variables as loop counters (revision 113)



