6

recently I learned about the two's compliment method of representing both positive and negative integers in the base two system. I then tried to see this in action using java with the following short code:

int a=2147483647;
System.out.println("a: "+a);
System.out.println("a+1: "+(a+1));
short b=32767;
System.out.println("b: "+b);
System.out.println("b+1: "+(b+1));

Which outputs:

a: 2147483647

a+1: -2147483648

b: 32767

b+1: 32768

Which confuses me because I would think that b+1, being represented in binary as 011111111111111, would turn into 1000000000000000, or in decimal, -32768. What's going on?

Community
  • 1
  • 1
Brown Philip
  • 219
  • 1
  • 3
  • 12

5 Answers5

10

Although b is a short, the expression (b + 1) is an int. The right operand is an int, the left operand is promoted to an int, and the expression is the promoted type of the operands.

From the Java Language Specification, 5.6.2. Binary Numeric Promotion:

Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

  • 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.

Note that this last promotion occurs even if both operands are of short type. You can't avoid promotion to an int with (b + (short) 1).

From 15.18.2. Additive Operators (+ and -) for Numeric Types

The type of an additive expression on numeric operands is the promoted type of its operands.

Community
  • 1
  • 1
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • 3
    It does describe this in the excerpt above, but I would emphasize here is that `short` operands are promoted to `int`, even if both are `short`s. So `short a = 32767; short b = 1; System.out.println(a + b);` would still print `32768`; this is slightly surprising, hence worth calling out explicitly. – Andy Turner Mar 08 '17 at 22:02
  • 1
    @AndyTurner - Good catch, I worded that incorrectly. Fixed above. – Andy Thomas Mar 08 '17 at 22:04
3

doing + automatically promotes short to int. Do this and you will see the overflow.

System.out.println("b+1: "+(short)(b+1)); //-32768

From the Java Language Specification, 5.6.2. Binary Numeric Promotion:

Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

  • 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.

Notice the last rule, so essentially that means that even if they are both shorts, they will be promoted to int, this can't be avoided.

you could:

short b= 32767;
short d= 12;
System.out.println("b+1: "+ (d+b)); // 32779

And the answer would still be valid.

Eddie Martinez
  • 13,582
  • 13
  • 81
  • 106
3

No need for confusion, try this:

short b = 32767;
short c = b + 1;

What do you get? Right, you get:

error: incompatible types: possible lossy conversion from int to short short c = b + 1;

So, what happens at your line? System.out.println("b+1: "+(b+1));?

Well, b+1 is too big for short, as you said correctly, but here you add an int to it, making the result an int as well. And 32768 is a valid int.

As others already pointed out, if you explicitly cast it down to (short) you get what you asked for.

On the other hand that does not work for short c = b + 1; as here the declared type is a short, while the actual type is an int.

short c = (short) (b + 1); solves that "problem"

  • @andy-turner Actually I do: https://repl.it/GNMT/1 (same in Scala with a `val c: Short = Short.MaxValue + 1` -> error: type mismatch; found: Int, required: Short) –  Mar 08 '17 at 22:05
  • Spoke too soon :) Yes, I checked it and found it too. That surprises me; I'd have thought that the automatic narrowing check on constant values would be able to know the warning was unnecessary. – Andy Turner Mar 08 '17 at 22:06
  • 1
    Aaah, I see. It's because the constant value definitely doesn't fit into the `short` range that you still get the warning. You don't get the warning for `final short b = 32766;`. – Andy Turner Mar 08 '17 at 22:07
2

1 is an int literal. When you compute b+1, you in fact promote b to an int and then add 1, resulting in 32768, which is a perfectly legal int value. If you cast it down to a short again, you'll see the overflow you're expecting (-32768):

System.out.println("b+1: " + (short)(b + 1));
Mureinik
  • 297,002
  • 52
  • 306
  • 350
2

As others have noted, addition promotes the operands to int.

Note that the += operator automatically does the casting back to short:

short b=32767;
System.out.println(b + 1);  // 32768, because of integer promotion.

b += 1;                     // Equivalent to b = (short)(b + 1);
System.out.println(b);      // -32768

b++;/++b; would yield the same result as b += 1.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243