Because floating-point numbers can represent fractions, it is often mistakenly assumed that they can represent any simple fraction exactly. In fact, floating-point numbers are subject to precision limitations just as integers are, and binary floating-point numbers cannot represent all decimal fractions exactly, even if they can be represented in a small number of decimal digits.
In addition, because floating-point numbers can represent large values, it is often mistakenly assumed 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 may not change that value within the available precision. Consequently, floating-point variables should not be used as loop counters.
Noncompliant Code Example
In this noncompliant code example, a floating-point variable is used as a loop counter. The decimal number 0.1 is a repeating fraction in binary and cannot be exactly represented as a binary floating-point number.
for (float x = 0.1f; x <= 1.0f; x += 0.1f) { // ... }
This loop is executed only nine times. (If the value of x
is printed inside the loop, the following values appear: 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.70000005, 0.8000001, 0.9000001.)
Compliant Solution
In this compliant solution, the loop counter is an integer from which the floating-point value is derived.
for (int count = 1; count <= 10; count += 1) { float x = count/10.0f; // ... }
Noncompliant Code Example
In this noncompliant code example, a floating-point loop counter is incremented by an amount that is too small to change its value given its precision.
for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) { /* ... */ }
This produces an infinite loop.
Compliant Solution
In this compliant solution, the loop counter is an integer from which the floating-point value is derived. Additionally, a double
is used instead of a float
to gain enough precision.
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.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FLP30- J |
low |
probable |
low |
P6 |
L2 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Other Languages
This rule appears in the C Secure Coding Standard as FLP30-C. Do not use floating point variables as loop counters.
This rule appears in the C++ Secure Coding Standard as FLP30-CPP. Do not use floating point variables as loop counters.
References
[[JLS 05]] Section 4.2.3, Floating-Point Types, Formats, and Values
[[Bloch 05]] Puzzle 34: Down for the Count
FLP04-J. Check floating point inputs for exceptional values 06. Floating Point (FLP) FLP31-J. Convert integers to floating point for floating point operations