Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Working with string representations of floating point values can produce incorrect conclusions about the precision of the values. For example, consider the conversion of a value from type float to type double, a widening primitive conversion. Refer to the guideline FLP10-J. Beware of precision loss when converting primitive integers to floating-point for more details about such conversions.

String representations of floating-point numbers shall should not be compared or inspected. When the value of a float variable must be represented exactly using the double type, an explicit assignment is more appropriate than first converting the floating point value to a String and then to a doubleIf they are used, significant care needs to be taken to ensure expected behavior.

Noncompliant Code Example (String Comparison)

This noncompliant code example attempts a string-based comparison of a floating-point number.

Code Block
bgColor#FFCCCC

int i = 1;
String s = Double.valueOf(i / 1000.0).toString();
if (s.equals("0.001")) {
  // ...
}

However s actually contain the string "0.0010". Consequently, the comparison unexpectedly fails.

Noncompliant Code Example (Regex)

This noncompliant code example attempts to mitigate the extra trailing zero by using a regular expression on the string before comparing it.

Code Block
bgColor#FFCCCC

int i = 1;
String s = Double.valueOf(i / 1000.0).toString();
s = s.replaceFirst("[.0]*$", "");
if (s.equals("0.001")) {
  // ...
}

Thie comparison does succeed on this code.

However, the comparison fails on this similar code, which uses 1/10000.0 instead of 1/1000.0incorrectly compares the decimal string literal generated by 1/10000.0. The string produced is not 0.00010 but 0001 but rather 1.0E-4.

Code Block
bgColor#FFCCCC

int i = 1;
String s = Double.valueOf(i / 10000.0).toString();
s = s.replaceFirst("[.0]*$", "");
if (s.equals("0.0001")) {
  // ...
}

Compliant Solution (String Comparison)

This compliant solution uses the BigDecimal class to avoid precision lossthe conversion into scientific notation. It then performs a numeric comparison, which passes as expected.

Code Block
bgColor#ccccff

int i = 1;
BigDecimal d = new BigDecimal(Double.valueOf(i / 100010000.0).toString());
if (d.compareTo(new BigDecimal("0.0010001")) == 0) {
  // ...
}

Risk Assessment

Relying on Comparing or inspecting the string representation of floating-point types can result in imprecise valuesvalues may have unexpected results.

Guideline

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FLP09

NUM11-J

low

Low

likely

Likely

medium

Medium

P6

L2

Automated Detection

TODO

Related Vulnerabilities

HV-192

Bibliography

Wiki Markup
\[[API 2006|AA. Bibliography#API 06]\] 
\[[JLS 2005|AA. Bibliography#JLS 05]\]


Android Implementation Details

Comparing or inspecting the string representation of floating-point values may have unexpected results on Android.

Bibliography


...

Image Added Image Added Image AddedFLP08-J. Do not construct BigDecimal objects from floating-point literals      03. Floating Point (FLP)      04. Object Orientation (OBJ)