Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: lots of wordsmithing & code tweaking. (didn't change coding idea tho)

String representations of floating point values can lead to incorrect conclusions about the precision of the values. For example, consider converting a value of type float to the type double, a widening primitive conversion. Refer to the guideline FLP10-J. Do not cast primitive integer types to floating-point types without range checks for more details about such conversions. When the value of the 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 double.

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 obtains the result of 1/1000.0 and represents it as a String. However, even though the resulting value is precise, an extra zero digit is appended at the end. Any operations on the string, such as comparisons, can yield incorrect results.

Code Block
bgColor#FFCCCC
int i = 1;
String s = Double.valueOf (i / 1000.0).toString();
s //= s contains 0.0010
if.replaceFirst("[.0]*$", "");
if (s.equals("0.001")) { // Fails
  // Do something...
}

Noncompliant Code Example

Thie comparison does succeed on this code.

However, the comparison fails on this similar code, which uses 1/10000.0 instead of 1/1000.0. The string produced is not 0.00010 but rather 1.0E-4This noncompliant code example attempts to use a regular expression to eliminate the trailing zeros. However, even though this works for 1/1000.0, for 1/10000.0, it produces the string 1.0E-4, which the regular expression is unable to process as expected. Subsequent comparison operations can still fail.

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

Compliant Solution (String Comparison)

This compliant solution uses the BigDecimal class and strips the trailing zeros so that future operations do not failto avoid precision loss. It then performs a numeric comparison, which passes as expected.

Code Block
bgColor#ccccff
int i = 1;
BigDecimal d = new BigDecimal(Double.valueOf (i / 1000.0).toString()).stripTrailingZeros();
if (d.compareTo(new BigDecimal("0.001")) == 0) { // Passes
  // Do something...
}

Risk Assessment

Relying on the string representation of floating point types can result in imprecise values.

...