FLP37-C. 浮動小数点値の比較にオブジェクト表現を使用しない
浮動小数点数の値のオブジェクト表現は処理系定義である。__STDC_IEC_559__
マクロを定義する処理系では、IEC 60559 浮動小数点標準に準拠しなければならず、一般に IEEE 754 浮動小数点演算と呼ばれるものが使用される[ISO/IEC 9899:2011]。IEC 60559 が使用する浮動小数点オブジェクトの表現は、今日最も利用されている浮動小数点オブジェクト表現の1つである。
全ての浮動小数点オブジェクト表現は、特定のビットパターンを使って浮動小数点数の値をエンコードする。一方で、浮動小数点数として値が等しいかどうかは、値を表現するビットパターンが等しいかどうかで決まるわけではない。例えば、IEC 60559 などのように浮動小数点フォーマットが負のゼロをサポートしている場合、-0.0
と 0.0
は等値として扱われるべきだが、オブジェクト表現上のビットパターンは同一ではない。同様に、2つの浮動小数点数がどちらも NaN である場合、ビットパターンは同一だが、等値ではないものとして扱われなければならない。
浮動小数点数のオブジェクト表現を memcmp()
を呼び出すなどの手段で直接比較してはならない。2つの浮動小数点数が等値かどうかを調べるには、等価演算子 (==
や !=
) を用いるべきである。
違反コード
次の違反コード例では、memcmp()
を使って2つの構造体が等価であるか比較している。しかし、構造体には浮動小数点オブジェクトが含まれるため、コードは意図した通りに動作しない。
#include <stdbool.h>
#include <string.h>
struct S {
int i;
float f;
};
bool are_equal(const struct S *s1, const struct S *s2) {
if (!s1 && !s2)
return true;
else if (!s1 || !s2)
return false;
return 0 == memcmp(s1, s2, sizeof(struct S));
}
適合コード
次の適合コードでは、構造体のメンバー同士を比較している。
#include <stdbool.h>
#include <string.h>
struct S {
int i;
float f;
};
bool are_equal(const struct S *s1, const struct S *s2) {
if (!s1 && !s2)
return true;
else if (!s1 || !s2)
return false;
return s1->i == s2->i &&
s1->f == s2->f;
}
リスク評価
浮動小数点数のオブジェクト表現を使って比較を行うと、間違った等値演算結果が得られ、結果としてプログラムの予期せぬ動作や間違った結果を招く恐れがある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FLP37-C | 低 | 低 | 中 | P2 | L3 |
参考情報
[ISO/IEC 9899:2011] | 附属書 F, "IEC 60559 floating-point arithmetic" |
翻訳元
これは以下のページを翻訳したものです。
FLP37-C. Do not use object representations to compare floating-point values (revision 1)