Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

When using binary operators with mixed operand sizes, be aware that some of the narrower operands may be promoted to a wider type, to match the type of the other operand. For example in the expression 'a ' == 42, the field 'a' which is shorter than an int will be promoted to an int before the comparison is carried out.

Wiki Markup
According to the Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\], section 4.2.2 "Integer Operations":

If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6). Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.

Wiki Markup
The Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\] section 5.6 "Numeric Promotions" describes numeric promotion as: 

...

Widening conversions resulting from integer promotions preserve the overall magnitude of the number. However, promotions in which the operands are converted from a numeric type such as an integer int to a float or a long to a double, are particularly pernicious (see INT33-J. Do not cast numeric types to wider floating-point types without range checking for more details). These implicit casts can lead to an undesirable loss in precision.

These conversions can happen with the following operators : multiplicative operators (%, *, /), additive operators (+, -), comparison operators (<, >, <=, >=) and equality (==, !=) and the integer bitwise operators (&, |, ^).

In the following example, a is promoted to a double before the + operator is applied.

...

In this noncompliant code example, the statement big * one carries out a binary operation. As big is an int and one is of type float, big is promoted to a float. This implicit case cast results in loss of precision.

Code Block
bgColor#ffcccc
class Test{
  public static void main(String[] args){
    int big = 1999999999;
    float one = 1.0f;
    System.out.println(big*one); // binary operation, loses precision due to implicit cast
    double big_float = big;
    System.out.println(big_float*one); // double is a wider type, preserves precision
  }
}

The output produced is :

...

2.0E9

...

Whereaswhereas, the expected output is :

...

1.999999999E9

...

.

...

Compliant solution

In this case, a double should be used instead of a float for a safe widening primitive conversion caused by integer promotion.

Code Block
bgColor#ccccff
class Test{
  public static void main(String[] args){
    int big = 1999999999;
    double one = 1.0d; // double instead of float
    System.out.println(big*one);
    double big_float = big;
    System.out.println(big_float);
  }
}

The output is as expected :

...

This produces the required output of 1.999999999E9. This is the value that is obtained when an int is assigned (implicitly cast) to a double.

Risk assessment

Failing to consider integer promotions while when dealing with floating point and integer operands together, can result in loss of precision.

...