You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 73 Next »

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, discarding information about any possible fractional remainder. Furthermore, there can be loss of precision when converting integers to floating-point values. See rule "NUM13-J. Beware of precision loss when converting primitive integers to floating-point" for additional information. Correct programming of expressions that mix integer and floating-point operations or values requires careful consideration.

Operations that could suffer from integer overflow or loss of a fractional remainder should be performed on floating-point values rather than integral values.

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. The results of the integral operations are truncated to the nearest integer, and can also overflow. As a result, the floating-point variables d, e, and f are initialized incorrectly because the truncation and overflow take place before the conversion to floating point.

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

Note that the calculation for c violates rule "NUM00-J. Detect or prevent integer overflow."

Compliant Solution (Floating-Point Literal)

This compliant solution performs the multiplication and division operations on floating-point values, avoiding both the truncation and the overflow seen in the noncompliant code example. In every operation, at least one of the operands is of a floating-point type, thereby forcing floating-point multiplication and division, and avoiding truncation and overflow.

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, but a precise representation of the value of c would require 56 mantissa bits. Consequently, the value of c is rounded to the nearest value that can be represented by 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 truncation and overflow 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 operation 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;

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. Consequently, the value of f is not precise before or after the multiplication. The explanation and consequences are identical to those stated above.

Exceptions

NUM13-EX0: 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, using integer arithmetic eliminates the need to use the floor() method. 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.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

NUM13-J

low

probable

low

P6

L2

Automated Detection

Automated detection is not feasible in the general case. Heuristic checking could be useful.

Related Guidelines

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="1f5ed1f1-3d37-4240-8093-71083ea83846"><ac:plain-text-body><![CDATA[

[java:[JLS 2005

AA. Bibliography#JLS 05]]

[[§5.1.2, Widening Primitive Conversion"

http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.2]

]]></ac:plain-text-body></ac:structured-macro>


      03. Numeric Types and Operations (NUM)      NUM13-J. Beware of precision loss when converting primitive integers to floating-point

  • No labels