Numeric promotions are used to convert the operands of a numeric operator to a common type so that an operation can be performed. When using arithmetic operators with mixed operand sizes, narrower operands are promoted to the type of the wider operand.

## Promotion Rules

The *Java Language Specification* (JLS), §5.6, "Numeric Promotions" [JLS 2013], describes numeric promotion as the following:

- If any of the operands is of a reference type, unboxing conversion is performed.
- If either operand is of type
`double`

, the other is converted to`double`

.- Otherwise, if either operand is of type
`float`

, the other is converted to`float`

.- Otherwise, if either operand is of type
`long`

, the other is converted to`long`

.- Otherwise, both operands are converted to type
`int`

.

Widening conversions, resulting from integer promotions, preserve the overall magnitude of the number. However, promotions in which the operands are converted from an `int`

to a `float`

or from a `long`

to a `double`

can cause a loss of precision. (See NUM13-J. Avoid loss of precision when converting primitive integers to floating-point for more details.)

These conversions can occur when using the 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:

int a = some_value; double b = some_other_value; double c = a + b;

In the following program fragment, `b`

is first converted to `int`

so that the `+`

operator can be applied to operands of the same type:

int a = some_value; char b = some_character; if ((a + b) > 1.1f) { // Do something }

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 `|=`

.

According to the JLS, §15.26.2, "Compound Assignment Operators" [JLS 2013],

A compound assignment expression of the form

`E1 op= E2`

is equivalent to`E1 = (T)((E1) op (E2))`

, where`T`

is the type of`E1`

, except that`E1`

is evaluated only once.

That is, the compound assignment expression implicitly casts the resulting computation to the type of the left-hand operand.

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`

, then `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)`

.

int big = 1999999999; float one = 1.0f; // Binary operation, loses precision because of implicit cast System.out.println(big * one);

In this case, numeric promotions require that `big`

be promoted to the type `float`

before the multiplication occurs, resulting in loss of precision. (See NUM13-J. Avoid loss of precision when converting primitive integers to floating-point.). This code outputs 2.0E9 rather than 1.999999999E9.

## 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:

int big = 1999999999; double one = 1.0d; // Double instead of float System.out.println(big * one);

This solution produces the expected output of 1.999999999E9, which is the value obtained when an `int`

is assigned (implicitly cast) to a `double`

.

See also NUM50-J. Convert integers to floating point for floating-point operations for more information about mixing integer and floating-point arithmetic.

## Noncompliant Code Example (Left Shift)

This noncompliant code example shows integer promotion resulting from the use of the bitwise OR operator.

byte[] b = new byte[4]; int result = 0; for (int i = 0; i < 4; i++) { result = (result << 8) | b[i]; }

Each 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]. This causes `result`

to contain a value other than the concatenation of the four array elements.

## Compliant Solution (Left Shift)

This compliant solution masks off the upper 24 bits of the byte array element to achieve the intended result:

byte[] b = new byte[4]; int result = 0; for (int i = 0; i < 4; i++) { result = (result << 8) | (b[i] & 0xff); }

## Noncompliant Code Example (Compound Addition and Assignment)

This noncompliant code example performs a compound assignment operation.

int x = 2147483642; // 0x7ffffffa x += 1.0f; // x contains 2147483647 (0x7fffffff) // after the computation

The compound operation involves an `int`

value that contains too many significant bits to fit in the 23-bit mantissa of a Java `float`

, causing the widening conversion from `int`

to `float`

to lose precision. The resulting value is frequently unexpected.

## Compliant Solution (Compound Addition and Assignment)

For defensive programming purposes, 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`

.

double x = 2147483642; // 0x7ffffffa x += 1.0; // x contains 2147483643.0 (0x7ffffffb.0) as expected

## Noncompliant Code Example (Compound Bit Shift and Assignment)

This noncompliant code example uses a compound right-shift operator for shifting the value of `i`

, bit.

short i = -1; i >>>= 1;

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. As a `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 performs an implicit narrowing conversion, discarding the 16 higher-order bits. The final result is again `0xffff`

, or `-1`

.

## Compliant Solution (Compound Bit Shift and Assignment)

This compliant solution applies the compound assignment operator to an `int`

, which does not require widening and subsequent narrowing. Consequently, `i`

gets the value `0x7fffffff`

.

int i = -1; i >>>= 1;

## Applicability

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

## Automated Detection

## Bibliography

Puzzle 9, "Tweedledum" | |

"BIT: Bitwise OR of Signed Byte Value" | |

[JLS 2013] | §4.2.2, "Integer Operations" |

## 3 Comments

## Kirk Sayre

This recommendation can refer to EXP04-J and EXP05-J as other examples of problems that can arise due to implicit integer promotions.

## Robert Seacord (Manager)

Please add a declaration for the array b in the left shift examples, so we can see clearly that it is a byte array.

## Fred Long

Done.