
Incautious use of integer arithmetic to calculate a value for assignment to a floating-point variable can lead to loss of information. Recall, for example, that integer arithmetic always produces integral results, consequently losing information about any possible fractional remainder. Further, there can be loss of precision when converting integers to floating-point values; see guideline FLP10-J. Avoid casting primitive integer types to floating-point types without range checks for additional information. Correct programming of expressions that mix integer and floating point operations or values requires careful consideration.
Noncompliant Code Example
In this noncompliant code example, the division and multiplication operations are performed on integral values; the results of these operations are then converted to floating-point. Consequently, the floating-point variables d
, e
, and f
are initialized incorrectly because the integral operations take place before the conversion to floating-point. The results of the integral operations are truncated to the nearest integer, and can also overflow.
short a = 533; int b = 6789; long c = 4664382371590123456L; float d = a / 7; // d is 76.0 (truncated) double e = b / 30; // e is 226.0 (truncated) double f = c * 2; // f is -9.1179793305293046E18 due to integer overflow
Compliant Solution (Floating Point Literal)
This compliant solution performs the multiplication and division operations on floating point values, thus avoiding both the truncation and the integer overflow seen in the noncompliant code example. The approach used is to ensure that at least one of the operands of each of the division or multiplication operations is of a floating-point type.
short a = 533; int b = 6789; long c = 4664382371590123456L; float d = a / 7.0f; // d is 76.14286 double e = b / 30.; // e is 226.3 double f = (double)c * 2; // f is 9.328764743180247E18
Note that the original value of c
cannot be represented exactly as a double
. The representation of type double
has only 48 mantissa bits; an exact representation of the value of c
would require 56 mantissa bits. Consequently, the value of c
is rounded to the nearest representable value of type double
, and the computed value of f
(9.328764743180247E18) differs from the exact mathematical result (9328564743180246912). This loss of precision is one of many reasons why correct programming of expressions that mix integer and floating point operations or values requires careful consideration. Even with this loss of precision, the computed value of f
is nevertheless far more accurate than that produced in the noncompliant example above.
Compliant Solution
This compliant solution eliminates the initialization errors by storing the integers in the floating-point variables before performing the arithmetic operations. As above, this ensures that at least one of the operands of each of the division or multiplication operations is a floating-point number; consequently, the operations are performed on floating-point values.
short a = 533; int b = 6789; long c = 4664382371590123456L; float d = a; double e = b; double f = c; //Note: truncation on conversion to double d /= 7; // d is 76.14286 e /= 30; // e is 226.3 f *= 2; // f is 9.328764743180247E18
As in the previous compliant example, the value of c
cannot be represented exactly as a double
. The explanation and consequences are identical to those stated above.
Exceptions
FLP02-EX1: It is acceptable to perform operations using a mix of integer and floating point values when deliberately exploiting the properties of integer arithmetic before conversion to floating point; for example, obviating the need to use the floor()
method by allowing truncation to integer values to perform the equivalent operation. Any such code must be clearly documented to help future maintainers understand that this behavior is intentional.
Risk Assessment
Improper conversions between integers and floating point values can yield unexpected results, especially from precision loss. In some cases, these unexpected results can involve overflow or undefined behavior.
Guideline |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FLP02-J |
low |
probable |
low |
P6 |
L2 |
Automated Detection
Automated detection is not feasible in the general case. Heuristic checking could be useful.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Related Guidelines
C Secure Coding Standard: FLP33-C. Convert integers to floating point for floating point operations
C++ Secure Coding Standard: FLP33-CPP. Convert integers to floating point for floating point operations
Bibliography
[[JLS 2005]] Section 5.1.2, "Widening Primitive Conversion"
FLP01-J. Take care in rearranging floating point expressions 07. Floating Point (FLP) FLP03-J. Range check before casting floating point numbers to narrower types