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

FLP30-C. 浮動小数点変数をループカウンタに使用しない

浮動小数点数は実数値を表現しているため、単純な有理数などは正確に表現できると考えられがちであるが、これは間違いである。浮動小数点数には整数と同様に精度の限界があり、全ての実数を厳密に表現できるわけではない。10進数としては小さい桁数で表現できる値が、2進数の浮動小数点数としては正確に表現できない場合がある。

加えて、浮動小数点数は大きな値を表現できるため、そのような大きな値の有効桁数全てを表現できると考えられることが多いが、これもまた間違いである。浮動小数点数は固定長の精度ビット(significand とも呼ばれる)と指数ビット(exponent)を使って広い範囲の値を表現するため、有効桁数はごく限られたものになる。

処理系によって精度の限界は異なる。コードの可搬性を維持するためには、ループカウンタに浮動小数点変数を使ってはいけない。この話題については、[Goldberg 1991] を参照すること。

違反コード

以下の違反コード例では、ループカウンタとして浮動小数点変数を使っている。10進小数 0.1 は2進数では循環小数になるので、2進の浮動小数点数として正確に表現することができない。処理系によって異なるが、ループは 9 回あるいは 10 回繰り返される。

void func(void) {
  for (float x = 0.1f; x <= 1.0f; x += 0.1f) {
    /* ループは9回あるいは10回繰り返す */
  }
}

たとえば、GCC あるいは Microsoft Visual Studio 2013 でコンパイルし、x86 プロセッサで実行した場合、ループは 9 回しか評価されない。

適合コード

以下の適合コードでは、ループカウンタに整数を使い、ループカウンタから浮動小数点の数値を計算している。

#include <stddef.h>

void func(void) {
  for (size_t count = 1; count <= 10; ++count) {
    float x = count / 10.0f;
    /* ループはちょうど10回繰り返す */
  }
}
違反コード

次の違反コード例では、浮動小数点数であるループカウンタをインクリメントしているが、この精度では値が小さすぎてカウンタの値が変わらない。

void func(void) {
  for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) {
    /* ループが終了しない可能性がある */
  }
}

このコードは多くの処理系で無限ループになる。

適合コード

次の適合コードでは、ループカウンタに整数を使い、カウンタの値を使って浮動小数点数の値を計算している。変数 x は、先の違反コード例のような丸めエラーが発生しないように計算を行なっている。

void func(void) {
  for (size_t count = 1; count <= 10; ++count) {
    float x = 1.00000000.0f + (count * 1.0f);
    /* ループはちょうど10回繰り返す */
  }
}
リスク評価

ループカウンタに浮動小数点変数を使用するとプログラムの予期せぬ動作につながる可能性がある。

ルール

深刻度

可能性

修正コスト

優先度

レベル

FLP30-C

P6

L2

自動検出

ツール

バージョン

チェッカー

説明

Clang 3.9 (prerelease) cert-flp30-c Checked by clang-tidy
CodeSonar 4.2 LANG.STRUCT.LOOP.FPC Float-typed loop counter

Compass/ROSE

 

 

 

ECLAIR 1.2 CC2.FLP30 Fully implemented

Fortify SCA

5.0

 

Can detect violations of this rule with CERT C Rule Pack

LDRA tool suite

9.5.6

39 S

Fully implemented

Parasoft C/C++test 9.5 MISRA-065 Fully implemented
Polyspace Bug Finder R2016a MISRA2012-RULE-14_1, MISRA2012-DIR-1_1 Fully implemented
PRQA QA-C 8.2 3340 Partially implemented
SonarQube C/C++ Plugin 3.11 S2193 Fully implemented
関連するガイドライン
SEI CERT C++ Coding Standard FLP30-CPP. Do not use floating-point variables as loop counters
Java セキュアコーディングスタンダード CERT/Oracle 版 NUM09-J. 浮動小数点数型変数をループカウンタとして使用しない
ISO/IEC TR 24772:2013 Floating-Point Arithmetic [PLF]
MISRA C:2012 Directive 1.1 (required)
Rule 14.1 (required)
参考資料
[Goldberg 1991]  
[Lockheed Martin 05] AV Rule 197
翻訳元

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

FLP30-C. Do not use floating-point variables as loop counters (revision 96)

Top へ

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