Because floating-point numbers can represent fractions, programmers often mistakenly assume that they can represent any simple fraction exactly. In fact, floating-point numbers are subject to range limitations just as integers are. Furthermore, limited-precision binary floating-point numbers cannot represent all decimals precisely, even when the decimals can be represented in a small number of digits.
In addition, because floating-point numbers can represent large values, programmers often mistakenly assume that they can represent all digits of those values. To gain a large dynamic range, floating-point numbers maintain a fixed number of bits of precision and an exponent. Incrementing a large floating-point value might not change that value within the available precision.
Consequently, floating-point variables must not be used as loop counters.
Noncompliant Code Example
This noncompliant code example uses a floating-point variable as a loop counter. The decimal number 0.1 can not be precisely represented as a float
or even as a double
.
for (float x = 0.1f; x <= 1.0f; x += 0.1f) { System.out.println(x); }
This loop executes only nine times, and produces the following output:
0.1 0.2 0.3 0.4 0.5 0.6 0.70000005 0.8000001 0.9000001
Compliant Solution
This compliant solution uses an integer loop counter from which the desired floating-point value is derived.
for (int count = 1; count <= 10; count += 1) { float x = count/10.0f; System.out.println(x); }
Noncompliant Code Example
This noncompliant code example uses a floating-point loop counter that is incremented by an amount that is too small to change its value given the precision.
for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) { /* ... */ }
The code loops forever on execution.
Compliant Solution
This compliant solution uses an integer loop counter from which the floating-point value is derived. Additionally, it uses a double
so that the available precision suffices to represent the desired values.
for (int count = 1; count <= 10; count += 1) { double x = 100000000.0 + count; /* ... */ }
Risk Assessment
Using floating-point loop counters can lead to unexpected behavior.
Guideline |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
NUM07-J |
low |
probable |
low |
P6 |
L2 |
Automated Detection
Automated detection of floating-point loop counters is straightforward.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Related Guidelines
C Secure Coding Standard: FLP30-C. Do not use floating point variables as loop counters
C++ Secure Coding Standard: FLP30-CPP. Do not use floating point variables as loop counters
Bibliography
[[Bloch 2005]] Puzzle 34: Down for the Count
[[JLS 2005]] Section 4.2.3, Floating-Point Types, Formats, and Values
NUM11-J. Check floating point inputs for exceptional values 03. Floating Point (FLP) NUM08-J. Do not construct BigDecimal objects from floating-point literals