VOOZH about

URL: https://www.javacodegeeks.com/2015/02/inconsistent-operation-widen-rules-java.html

⇱ Inconsistent operation widen rules in Java - Java Code Geeks


Overview

When you perform a unary or binary operation in Java the standard behaviour is to use the widest operand (or a wider one for byte, short and char).  This is simple to understand but can be confusing if you consider what the optimal type is likely to be.

Multiplication

When you perform multiplication, you often get a much large number than either of the individual numbers in magnitude. i.e. |a*b| >> |a| and |a*b| >> |b| is often the case. And for small types this works as expected.

Consider this program:

public static void main(String[] args) throws IOException {
 System.out.println(is(Byte.MAX_VALUE * Byte.MAX_VALUE));
 System.out.println(is(Short.MAX_VALUE * Short.MAX_VALUE));
 System.out.println(is(Character.MAX_VALUE * Character.MAX_VALUE));
 System.out.println(is(Integer.MAX_VALUE * Integer.MAX_VALUE));
 System.out.println(is(Long.MAX_VALUE * Long.MAX_VALUE));
}

static String is(byte b) {
 return "byte: " + b;
}

static String is(char ch) {
 return "char: " + ch;
}

static String is(short i) {
 return "short: " + i;
}

static String is(int i) {
 return "int: " + i;
}

static String is(long l) {
 return "long: " + l;
}

which prints:

int: 16129
int: 1073676289
int: -131071
int: 1
long: 1

Only byte * byte and short * short doesn’t overflow as these have been widened.  char * char isn’t a meaningful operation even though it is allowed. But int * int does overflow even though we have a long type which could store this value without an overflow.  Both byte and short are widened implicitly but not int. long should really be widened but we don’t have a wider primitive type, which would have made sense once upon a time however a 64-bit primitive doesn’t seem so long these days.

Division

Division is a little strange in the sense that the divisor can widen the result. Having a wider divisor than the numerator doesn’t mean the result will be bigger (but is usually smaller)

System.out.println(is(Byte.MAX_VALUE / (byte) 1));
System.out.println(is(Byte.MAX_VALUE / (short) 1));
System.out.println(is(Byte.MAX_VALUE / (char) 1));
System.out.println(is(Byte.MAX_VALUE / (int) 1));
System.out.println(is(Byte.MAX_VALUE/ (long) 1));

prints

int: 127
int: 127
int: 127
int: 127
long: 127

When you divide a byte/byte you get an int even though you can’t get a value larger than a byte. (unless you divide Byte.MIN_VALUE by -1 in which case a short would do) and if you divide a byte/long you get a long even though the value still cannot be bigger than a byte.

Modulus

When you perform modulus a % b, the result cannot be bigger than b.  And yet modulus will wider a result rather than reduce it.

System.out.println(is(Byte.MAX_VALUE % Byte.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Short.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Character.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Integer.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Long.MAX_VALUE));
 
System.out.println(is(Byte.MAX_VALUE % (byte) 2));
System.out.println(is(Short.MAX_VALUE % (byte) 2));
System.out.println(is(Character.MAX_VALUE % (byte) 2));
System.out.println(is(Integer.MAX_VALUE % (byte) 2));
System.out.println(is(Long.MAX_VALUE % (byte) 2));

prints

int: 0
int: 127
int: 127
int: 127
long: 127
int: 1
int: 1
int: 1
int: 1
long: 1

If you modulus X by a number the result can’t get any wider/bigger than X, it can only get smaller.  However, the JLS say it must get wider. If you modulus X by a byte, the result can only ever be in the range of a byte.

👁 Photo of Peter Lawrey
Peter Lawrey
February 9th, 2015Last Updated: February 6th, 2015
0 90 2 minutes read
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz