Versions Compared

Key

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

...

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.

Promotion Rules

The JLS §5.6, "Numeric Promotions" describes numeric promotion as the following:

...

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

Examples

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

...

Here, b is first converted to int so that the + operator can be applied to operands of the same type. The result of (a+b) is then converted to a float, and the comparison operator is finally applied.

Compound Operators

Type coercion may occur when compound expressions are used with mixed operand types. Examples of compound assignment operators are +=, -=, *=, /=, &=, ^=, %=, <<=, >>=, >>>= and |=.

...

When the operands are different types, multiple conversions can occur. For example, when E1 is an int and E2 is either a long, a float, or a double, E1 is widened from type int to the type of E2 (before the "op"), followed by a narrowing conversion from the type of E2 back to type int (after the "op" but before the assignment).

Noncompliant Code Example (Multiplication)

In this noncompliant code example, a variable of type int (big) is multiplied by a value of type float one. In this case, numeric promotions require that big is promoted to the type float before the multiplication occurs, resulting in loss of precision. (See guideline "NUM17-J. Beware of precision loss when converting primitive integers to floating-point".)

...

This code outputs 2.0E9 and not 1.999999999E9 as expected.

Compliant Solution (Multiplication)

This compliant solution uses the double type, instead of float, as a safer means of handling the widening primitive conversion resulting from integer promotion.

...

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

Noncompliant Code Example (Left Shift)

Wiki Markup
This noncompliant code example shows integer promotion resulting from the use of the bit-wise OR operator. The byte array element is sign extended to 32 bits before it is used as an operand. If it originally contained the value {{0xff}}, it would contain {{0xffffffff}} \[[Findbugs 2008|AA. Bibliography#Findbugs 08]\].  

Code Block
bgColor#ffcccc
int result = 0;
for(int i = 0; i < 4; i++) 
  result = ((result << 8) | b[i]);

Compliant Solution (Left Shift)

This compliant solution continues to use integer promotion, but it masks off the upper 24 bits of the byte array element to achieve the intended result.

Code Block
bgColor#ccccff
int result = 0;
for (int i = 0; i < 4; i++) 
  result = ((result << 8) | (b[i] & 0xff));

Noncompliant Code Example (Compound Addition & Assignment)

This noncompliant code example performs a compound assignment operation. This operation involves an int value that contains too many significant bits to fit in the twenty-three bit mantissa of a Java float, causing the widening conversion from int to float to lose precision. The resulting value could surprise many programmers.

Code Block
bgColor#FFCCCC
public class Expr {
  public static void main(String[] args) {
    int x = 2147483642; // 0x7ffffffa
    x += 1.0f; // x contains 2147483647 (0x7fffffff) after the computation
  }
}

Compliant Solution (Compound Addition & Assignment)

To be safe, avoid using any of the compound assignment operators on variables of types byte, short, or char. Also, refrain from using a wider operand on the right hand side. In this compliant solution, all operands are of the Java type double.

Code Block
bgColor#ccccff
public class Expr {
  public static void main(String[] args) {
    double x = 2147483642; // 0x7ffffffa
    x += 1.0; // x contains 2147483643.0 (0x7ffffffb.0) as expected
  }
}

Noncompliant Code Example (Compound Bit Shift & Assignment)

This noncompliant code example uses a compound right shift operator for shifting the value of i, bit by bit. Unfortunately, the value of i remains the same. The value of i is first promoted to an int. This is a widening primitive conversion, so no data is lost. With short, -1 is represented as 0xffff. The conversion to int results in the value 0xffffffff, which is right shifted by 1 bit to yield 0x7fffffff. To store the value back into the short variable i, Java then performs an implicit narrowing conversion, discarding the 16 higher order bits. The final result is again 0xffff or -1.

Code Block
bgColor#FFCCCC
short i = -1;
i >>>= 1;

Compliant Solution (Compound Bit Shift & Assignment)

This compliant solution applies the compound assignment operator to an int which does not require widening and subsequent narrowing.

Code Block
bgColor#ccccff
int i = -1;
i >>>= 1;

Risk Assessment

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

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

NUM18-J

low

probable

medium

P4

L3

Automated Detection

Automated detection of numeric promotion is straightforward. Determining which promotions are problematic is infeasible in the general case. A heuristic approach could provide acceptable results.

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="31e7bdbb29040899-d5d90062-417742b3-b539a7b9-2a3afe4c21730be6317649e4"><ac:plain-text-body><![CDATA[

[[Bloch 2005

AA. Bibliography#Bloch 05]]

Puzzle 9: "Tweedledum"

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

 

Puzzle 31: "Ghost of Looper"

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="9af9c1d67733aa33-8ce449c5-4b7f48d1-89e395dc-357daa4e426ee367a7470634"><ac:plain-text-body><![CDATA[

[[Findbugs 2008

AA. Bibliography#Findbugs 08]]

"BIT: Bitwise OR of signed byte value"

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

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="4b49794fa9de24bc-807b2538-4ae54880-91f6a2c7-04ee349add533218dca1db49"><ac:plain-text-body><![CDATA[

[[JLS 2005

AA. Bibliography#JLS 05]]

[§4.2.2, "Integer Operations"

http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.2]

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

 

§5.6, "Numeric Promotions"

 

§15.26.2, "Compound Assignment Operators"

...