浮動小数点数の文字列表現を比較したり、その内容を調べたりしてはならない。
違反コード (文字列の比較)
以下の違反コードでは2つの浮動小数点数の文字列表現を比較している。
int i = 1; String s = Double.valueOf(i / 1000.0).toString(); if (s.equals("0.001")) { // ... }
s の値は文字列"0.0010" であるため、比較は予期せず失敗する。
違反コード (正規表現)
以下の違反コードでは、文字列の比較を行う前に、正規表現を用いて末尾の余分なゼロを取り除こうとしている。
int i = 1; String s = Double.valueOf(i / 1000.0).toString(); s = s.replaceFirst("[.0]*$", ""); if (s.equals("0.001")) { // ... }
上記のコードの比較は成功するが、似たような下記のコードでは失敗する。下記のコードでは、1/1000.0の代わりに1/10000.0を用いている。生成される文字列は0.00010ではなく、1.0E-4になる。
int i = 1; String s = Double.valueOf(i / 10000.0).toString(); s = s.replaceFirst("[.0]*$", ""); if (s.equals("0.0001")) { // ... }
適合コード (文字列の比較)
以下の適合コードでは、BigDecimalクラスを使用して浮動小数点数の精度の欠損を防いでいる。数値の比較も想定した通りに行われる。
int i = 1; BigDecimal d = new BigDecimal(Double.valueOf(i / 1000.0).toString()); if (d.compareTo(new BigDecimal("0.001")) == 0) { // ... }
リスク評価
浮動小数点数の文字列表現を比較したり内容を調べたりすると、予期せぬ結果が得られる場合がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
NUM11-J | 低 | 高 | 中 | P6 | L2 |
関連する脆弱性
Hibernate Validator バグレポート HV-192 はこのルールの違反例である。
参考文献
[API 2006] |
[JLS 2005] |
翻訳元
これは以下のページを翻訳したものです。
NUM11-J. Do not compare or inspect the string representation of floating-point values (revision 66)