Floating-point variables must not be used as loop counters. Limited-precision IEEE 754 floating-point types cannot represent
- all All simple fractions exactly.
- all All decimals precisely, even when the decimals can be represented in a small number of digits.
- all All digits of large values, meaning that incrementing a large floating-point value might not change that value within the available precision.
For the purpose of this rule, a loop counter is an induction variable that is used as an operand of a comparison expression that is used as the controlling expression of a do, while or for loop. An induction variable is a variable that gets increased or decreased by a fixed amount on every iteration of a loop [Aho 1986]. Furthermore, the change to the variable must occur directly in the loop body (rather than inside a function executed within the loop.)
This rule is a subset of NUM04-J. Do not use floating-point numbers if precise computation is required.
Noncompliant Code Example
This noncompliant code example uses a floating-point variable as a loop counter. The decimal number 0.1 cannot be precisely represented as a float
or even as a double
.
Code Block | ||
---|---|---|
| ||
for (float x = 0.1f; x <= 1.0f; x += 0.1f) {
System.out.println(x);
}
|
...
This compliant solution uses an integer loop counter from which the desired floating-point value is derived.:
Code Block | ||
---|---|---|
| ||
for (int count = 1; count <= 10; count += 1) {
float x = count/10.0f;
System.out.println(x);
}
|
...
This noncompliant code example uses a floating-point loop counter that is incremented by an amount that is typically too small to change its value given the precision.:
Code Block | ||
---|---|---|
| ||
for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) {
/* ... */
}
|
...
This compliant solution uses an integer loop counter from which the floating-point value is derived. Additionally, it uses a double
to ensure that the available precision suffices to represent the desired values. The solution also runs in strict floating-point (FP-strict) mode to guarantee portability of its results . See NUM06-J (see NUM53-J. Use the strictfp modifier for floating-point calculation consistency across platforms for more information).
Code Block | ||
---|---|---|
| ||
for (int count = 1; count <= 10; count += 1) {
double x = 100000000.0 + count;
/* ... */
}
|
...
Using floating-point loop counters can lead to unexpected behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
NUM09-J |
Low |
Probable |
Low | P6 | L2 |
Automated Detection
Automated detection of floating-point loop counters is straightforward.
Related Guidelines
Tool | Version | Checker | Description | |||||
---|---|---|---|---|---|---|---|---|
Parasoft Jtest |
| CERT.NUM09.FPLI |
Do not use floating point variables as loop |
indices | |||||||||
PVS-Studio |
| V6108 |
Related Guidelines
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="2f8799bb-4e50-467b-830b-28104a097c49"><ac:plain-text-body><![CDATA[
ISO/IEC TR 24772:2010 |
Floating-point Arithmetic [PLF |
] |
Bibliography
[Aho 1986] | |
Puzzle 34, "Down for the Count" | |
[JLS 2015] |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="3e6247c2-af57-480d-af3a-51fe014f1301"><ac:plain-text-body><![CDATA[
[[Bloch 2005
AA. Bibliography#Bloch 05]]
Puzzle 34. Down for the count
]]></ac:plain-text-body></ac:structured-macro>
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="086e151c-a3c4-4a71-b0c4-011a9a6a87f3"><ac:plain-text-body><![CDATA[
[[JLS 2005
AA. Bibliography#JLS 05]]
http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3]
]]></ac:plain-text-body></ac:structured-macro>
[Seacord 2015] |
...