lexicore
lexicore

Reputation: 43651

Why byte and short division results in int in Java?

In Java, if we divide bytes, shorts or ints, we always get an int. If one of the operands is long, we'll get long.

My question is - why does byte or short division not result in byte or short? Why always int?

Apparently I'm not looking for the "because JLS says so" answer, I am asking about the technical rationale for this design decision in the Java language.

Consider this code sample:

    byte byteA = 127;
    byte byteB = -128;
    short shortA = 32767;
    short shortB = -32768;
    int intA = 2147483647;
    int intB = - -2147483648;
    long longA = 9223372036854775807L;
    long longB = -9223372036854775808L;


    int byteAByteB = byteA/byteB;
    int byteAShortB = byteA/shortB;
    int byteAIntB = byteA/intB;
    long byteALongB = byteA/longB;

    int shortAByteB = shortA/byteB;
    int shortAShortB = shortA/shortB;
    int shortAIntB = shortA/intB;
    long shortALongB = shortA/longB;

    int intAByteB = intA/byteB;
    int intAShortB = intA/shortB;
    int intAIntB = intA/intB;
    long intALongB = intA/longB;

    long longAByteB = longA/byteB;
    long longAShortB = longA/shortB;
    long longAIntB = longA/intB;
    long longALongB = longA/longB;

byteA divided by byteB can't be anything but a byte, can it?
So why must byteAByteB be an int? Why can't shortALongB be short?
Why does intALongB have to be long, the result will always fit int, will it not?

Update

As @Eran pointed out, (byte)-128/(byte)-1 results in 128 which does not fit a byte. But why not short then?

Update 2

Next, as @Eran pointed out (again), (int) -2147483648 / (int) -1 also does not fit int but the result is nevertheless int, not long.

Upvotes: 4

Views: 3274

Answers (6)

Lawrence H
Lawrence H

Reputation: 7

This doesn't exactly answer your question, but I was doing a challenge using bytes for my entire program, and so I handled division like so:

byte value = 122;//Value being divided
byte divider = 2;//Divide value with this
byte result = 0;//Eventual result of pseudo-division
byte counter = 0;//Keep track of when to add 1 to the result

for (byte b = 0; b < value; b++)
{
    counter++;
    if (counter == divider)
    {
        counter = 0;
        result++;
    }
}
return (result);

This will keep "result" as a whole number and should divide "value" without having to use integers.

Upvotes: 0

Decrepit warrior
Decrepit warrior

Reputation: 11

Whenever you're defining a variable of type byte, whatever you type across from it should be of type byte.

That means it can only be a number in the range of a byte (-128 to 127).

However, when you type in an expression, for ex. byteA/byteB that is not the same as typing in a literal, for ex. the number 127.

This is the nature of Java - the integer is the default data type used for whole numbers.

By default when you're making an assignment of an expression, Java converts that into the default data type (integer) despite the fact that the result of the expression might be a valid value for a byte.

So what happens is that when you define a byte and assign an expression as the value of that byte, Java will need to convert it into an integer:

int byteAByteB = byteA / byteB;

However, you can get around that by casting the assigned expression and thus forsing Java to treat it as a byte.

byte byteAByteB = (byte) (byteA / byteB);

This way you're telling Java to treat that as a byte. (Can also be done with short, etc.)

Upvotes: 1

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36391

The main reason is that machines usually have only add instructions for their native integer type (and floats). This is why for many languages the least used type in an arithmetic expression is int (usually the type that correspond in some way to the basic machine integer type).

For example, i386 spec says:

ADD performs an integer addition of the two operands (DEST and SRC). The result of the addition is assigned to the first operand (DEST), and the flags are set accordingly. When an immediate byte is added to a word or doubleword operand, the immediate value is sign-extended to the size of the word or doubleword operand.

This means that internally any byte value is extended to an integer (or similar). After all this is reasonable as the processor is 32/64 bits and then perform any arithmetic in these sizes. If it could be possible to make arithmetic in bytes this is generally not considered as useful.

The JVM specs says that (for addition) you have : iadd, ladd, fadd, dadd. This just reflect the fact that underlying machines usually behave such. Any other choice could have been possible, probably at the price of performance degradation.

Upvotes: 5

Bathsheba
Bathsheba

Reputation: 234635

I guess it's something that was adopted from C, possibly via C++.

In those languages, an argument or arguments are always promoted to int if they are narrower types than an int. This happens before the expression is evaluated. Quite often it goes unnoticed since the resulting operation is converted to the type to which it is being assigned, and a compiler may well optimise out all the intermediate steps if there are no side effects.

In Java though it's not too pernicious. (In C and C++ it can catch you out: a multiplication of two large unsigned shorts can overflow the int, the behaviour of which is undefined.)

Note that if one of the arguments is larger than an int, then the type of the expression is the largest of the arguments types.

Upvotes: 3

Peter Lawrey
Peter Lawrey

Reputation: 533432

I believe the justification is that a simple rules creates least surprise. The result is always the wider type of the two (minimum being int), it doesn't depend on the operation.

A better approach might be to always widen +, *, - unless explicitly (or perhaps implicitly) narrowed. i.e. don't do overflow or underflow unless you use a cast. / for example could always be a double or long operation unless casted.

But C and thus Java doesn't do this.

In short, it has one simple rule for dealing with this, for better or worse.


See my rant here http://vanillajava.blogspot.co.uk/2015/02/inconsistent-operation-widen-rules-in.html

Upvotes: 3

Eran
Eran

Reputation: 393771

byteA divided by byteB can't be anything but a byte, can it?

It can be other than byte :

byteA = -128;
byteB = -1;
int div = byteA/byteB; // == 128, not a byte

Upvotes: 8

Related Questions