Mathematical operations on Java primitives? [duplicate] - java

Consider this code:
public class ShortDivision {
public static void main(String[] args) {
short i = 2;
short j = 1;
short k = i/j;
}
}
Compiling this produces the error
ShortDivision.java:5: possible loss of precision
found : int
required: short
short k = i/j;
because the type of the expression i/j is apparently int, and hence must be cast to short.
Why is the type of i/j not short?

From the Java spec:
5.6.2 Binary Numeric Promotion
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value of a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
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.
For binary operations, small integer types are promoted to int and the result of the operation is int.
EDIT: Why is it like that? The short answer is that Java copied this behavior from C. A longer answer might have to do with the fact that all modern machines do at least 32-bit native computations, and it might actually be harder for some machines to do 8-bit and 16-bit operations.
See also: OR-ing bytes in C# gives int

Regarding the motivation: lets imagine the alternatives to this behaviour and see why they don't work:
Alternative 1: the result should always be the same as the inputs.
What should the result be for adding an int and a short?
What should the result be for multiplying two shorts? The result in general will fit into an int, but because we truncate to short, most multiplications will fail silently. Casting to an int afterwards won't help.
Alternative 2: the result should always be the smallest type that can represent all possible outputs.
If the return type were a short, the answer would not always be representable as a short.
A short can hold values -32,768 to 32,767. Then this result will cause overflow:
short result = -32768 / -1; // 32768: not a short
So your question becomes: why does adding two ints not return a long? What should multiplication of two ints be? A long? A BigNumber to cover the case of squaring integer min value?
Alternative 3: Choose the thing most people probably want most of the time
So the result should be:
int for multiplying two shorts, or any int operations.
short if adding or subtracting shorts, dividing a short by any integer type, multiplying two bytes, ...
byte if bitshifting a byte to the right, int if bitshifting to the left.
etc...
Remembering all the special cases would be difficult if there is no fundamental logic to them. It's simpler to just say: the result of integer operations is always an int.

It just a design choice to be consistent with C/C++ which were dominate languages when Java was designed.
For example, i * j could be implemented so the type is promoted from byte => short, short => int, and int => long, and this would avoid overflows but it doesn't. (It does in some languages) Casting could be used if the current behaviour was desired, but the loss of some bits would be clear.
Similarly i / j could be prompted from byte/short => float or int/long => double.

Related

How type extension occurs in case of positives and negatives in Java?

Is there any difference between how type conversion happens in case of positive and negative numbers?
For example, if we have
short a = 100;
and put it to
int b = a;
if we change '100' to '-100', does it make any difference?
I tried to find it compiling in IDEA, but didn't find difference, but I have this questions from my mentor.
Disclaimer: Since this is a homework question, what I say here might not be the "expected" answer.
There are two conversions involved here. The first one is a narrowing primitive conversion from int (the literal 100 evaluates to a value of type int) to short. The second one is a widening primitive conversion from short to int.
The second conversion will never lose information, as per the JLS §5.1.2:
A widening primitive conversion does not lose information about the
overall magnitude of a numeric value in the following cases, where the
numeric value is preserved exactly:
from an integral type to another integral type
from byte, short, or char to a floating point type
from int to double
from float to double in a strictfp expression (§15.4)
The first conversion is done like this, according to the JLS §5.1.3
A narrowing conversion of a signed integer to an integral type T
simply discards all but the n lowest order bits, where n is the number
of bits used to represent type T. In addition to a possible loss of
information about the magnitude of the numeric value, this may cause
the sign of the resulting value to differ from the sign of the input
value.
Both -100 and 100 is representable with short, whose range is -65536...65535, so no information is lost here either.
In short, it doesn't matter whether you use 100 or -100, the result will be that b will store the value of 100 or -100 respectively.

How to perform unassigned sum with short variable with out converting in to integer in java

My requirement is to perform unassigned sum with short variables in java with out converting in to integer.
Please suggest is it possible to perform unassigned sum or not.
Java doesn't have an addition operator for short values. If you look at JLS 15.18.2 (Additive Operators (+ and -) for Numeric Types) you'll see that one of the first things that happens is:
Binary numeric promotion is performed on the operands (§5.6.2).
That will always convert short values into int, float, long or double values, depending on the other operand.
Basically, to perform 16-bit addition, you let the compiler convert both operands into 32 bits, do the addition, and then cast back:
(short) (a + b)
... being aware that this may lose information due to overflow when casting.

Rules governing narrowing of double to int

Please note I am NOT looking for code to cast or narrow a double to int.
As per JLS - $ 5.1.3 Narrowing Primitive Conversion
A narrowing conversion of a signed integer to an integral type T
simply discards all but the n lowest order bits, where n is the number
of bits used to represent type T.
So, when I try to narrow a 260 (binary representation as 100000100) to a byte then result is 4 because the lowest 8 bits is 00000100 which is a decimal 4 OR a long value 4294967296L (binary representation 100000000000000000000000000000000) to a byte then result is 0.
Now, why I want to know the rule for narrowing rule from double to int, byte etc. is when I narrow a double value 4294967296.0 then result is 2147483647 but when I narrow a long 4294967296L value then result is 0.
I have understood the long narrowing to int, byte etc. (discards all but the n lowest order bits) but I want to know what is going under the hoods in case of double narrowing.
I have understood the long narrowing to int, byte etc. (discards all but the n lowest order bits) but I want to know what is going under the hoods in case of double narrowing.
... I want to understand the why and how part.
The JLS (JLS 5.1.3) specifies what the result is. A simplified version (for int) is:
a NaN becomes zero
an Inf becomes "max-int" or "min-int"
otherwise:
round towards zero to get a mathematical integer
if the rounded number is too big for an int, the result becomes "min-int" or "max-int"
"How" is implementation specific. For examples of how it could be implemented, look at the Hotspot source code (OpenJDK version) or get the JIT compiler to dump some native code for you to look at. (I imagine that the native code maps uses a single instruction to do the actual conversion .... but I haven't checked.)
"Why" is unknowable ... unless you can ask one of the original Java designers / spec authors. A plausible explanation is a combination of:
it is easy to understand
it is consistent with C / C++,
it can be implemented efficiently on common hardware platforms, and
it is better than (hypothetical) alternatives that the designers considered.
(For example, throwing an exception for NaN, Inf, out-of-range would be inconsistent with other primitive conversions, and could be more expensive to implement.)
Result is Integer.MAX_VALUE when converting a double to an integer, and the value exceeds the range of an integer. Integer.MAX_VALUE is 2^31 - 1.
When you start with the double value 4294967296.0, it is greater than the greatest long value which is 2147483647 so the following rule is applied (from the page you cited) : The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long and you get 0x7FFFFFF = 2147483647
But when you try to convert 4294967296L = 0x100000000, you start from an integral type, so the rule is : A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits so if n is less than 32 (8 bytes) you just get a 0.

loss of precision when assigning to a variable

i had a doubt in assigning or casting to a proper data type.
byte a=3; //compiled
byte b=5; //compiled
byte c=a+b; //not compiled and reporting as possible loss of precision.
here first two statements are compiling even though we are assigning int literal to byte.but what about third statement i am doing the same as above and that too value of a+b is in the range of byte .why there is such error?
The general rule is that you can not use assignment to narrow an integer to a byte, because that is an unsafe narrowing conversion (most ints don't fit in a byte). Specifically, none of the allowed assignment conversions may narrow.
However, there is an exception specifically for this case:
A narrowing primitive conversion may
be used if the type of the variable is
byte, short, or char, and the value of
the constant expression is
representable in the type of the
variable.
This applies to a and b. The type of both variables is byte, and the values of both constant expressions clearly fit in a byte.
When you do the + operation on two bytes, they get implicitly converted to an int, so the result is an int as well. Therefore, you need another cast.
( The literal assignments in the first statement have nothing to do with it. )
I believe that addition performs binary numeric promotion, so a and b are being promoted to ints in the third statement.

Primitive type 'short' - casting in Java

I have a question about the primitive type short in Java. I am using JDK 1.6.
If I have the following:
short a = 2;
short b = 3;
short c = a + b;
the compiler does not want to compile - it says that it "cannot convert from int to short" and suggests that I make a cast to short, so this:
short c = (short) (a + b);
really works. But my question is why do I need to cast? The values of a and b are in the range of short - the range of short values is {-32,768, 32767}.
I also need to cast when I want to perform the operations -, *, / (I haven't checked for others).
If I do the same for primitive type int, I do not need to cast aa+bb to int. The following works fine:
int aa = 2;
int bb = 3;
int cc = aa +bb;
I discovered this while designing a class where I needed to add two variables of type short, and the compiler wanted me to make a cast. If I do this with two variables of type int, I don't need to cast.
A small remark: the same thing also happens with the primitive type byte. So, this works:
byte a = 2;
byte b = 3;
byte c = (byte) (a + b);
but this not:
byte a = 2;
byte b = 3;
byte c = a + b;
For long, float, double, and int, there is no need to cast. Only for short and byte values.
As explained in short C# (but also for other language compilers as well, like Java)
There is a predefined implicit conversion from short to int, long, float, double, or decimal.
You cannot implicitly convert nonliteral numeric types of larger storage size to short (see Integral Types Table for the storage sizes of integral types). Consider, for example, the following two short variables x and y:
short x = 5, y = 12;
The following assignment statement will produce a compilation error, because the arithmetic expression on the right-hand side of the assignment operator evaluates to int by default.
short z = x + y; // Error: no conversion from int to short
To fix this problem, use a cast:
short z = (short)(x + y); // OK: explicit conversion
It is possible though to use the following statements, where the destination variable has the same storage size or a larger storage size:
int m = x + y;
long n = x + y;
A good follow-up question is:
"why arithmetic expression on the right-hand side of the assignment operator evaluates to int by default" ?
A first answer can be found in:
Classifying and Formally Verifying Integer Constant Folding
The Java language specification defines exactly how integer numbers are represented and how integer arithmetic expressions are to be evaluated. This is an important property of Java as this programming language has been designed to be used in distributed applications on the Internet. A Java program is required to produce the same result independently of the target machine executing it.
In contrast, C (and the majority of widely-used imperative and
object-oriented programming languages) is more sloppy and leaves many important characteristics open. The intention behind this inaccurate language
specification is clear. The same C programs are supposed to run on a 16-bit,
32-bit, or even 64-bit architecture by instantiating the integer arithmetics of
the source programs with the arithmetic operations built-in in the target processor. This leads to much more efficient code because it can use the available
machine operations directly. As long as the integer computations deal only
with numbers being “sufficiently small”, no inconsistencies will arise.
In this sense, the C integer arithmetic is a placeholder which is not defined exactly
by the programming language specification but is only completely instantiated by determining the target machine.
Java precisely defines how integers are represented and how integer arithmetic is to be computed.
Java Integers
--------------------------
Signed | Unsigned
--------------------------
long (64-bit) |
int (32-bit) |
short (16-bit) | char (16-bit)
byte (8-bit) |
Char is the only unsigned integer type. Its values represent Unicode characters, from \u0000 to \uffff, i.e. from 0 to 216−1.
If an integer operator has an operand of type long, then the other operand is also converted to type long. Otherwise the operation is performed on operands of type int, if necessary shorter operands are converted into int. The conversion rules are exactly specified.
[From Electronic Notes in Theoretical Computer Science 82 No. 2 (2003)
Blesner-Blech-COCV 2003: Sabine GLESNER, Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Karlsruhe, Germany]
EDIT: Okay, now we know it's Java...
Section 4.2.2 of the Java Language Specification states:
The Java programming language provides
a number of operators that act on
integral values:
[...]
The numerical operators, which result
in a value of type int or long:
[...]The additive operators + and
- (§15.18)
In other words, it's like C# - the addition operator (when applied to integral types) only ever results in int or long, which is why you need to cast to assign to a short variable.
Original answer (C#)
In C# (you haven't specified the language, so I'm guessing), the only addition operators on primitive types are:
int operator +(int x, int y);
uint operator +(uint x, uint y);
long operator +(long x, long y);
ulong operator +(ulong x, ulong y);
float operator +(float x, float y);
double operator +(double x, double y);
These are in the C# 3.0 spec, section 7.7.4. In addition, decimal addition is defined:
decimal operator +(decimal x, decimal y);
(Enumeration addition, string concatenation and delegate combination are also defined there.)
As you can see, there's no short operator +(short x, short y) operator - so both operands are implicitly converted to int, and the int form is used. That means the result is an expression of type "int", hence the need to cast.
In C# and Java, the arithmatic expression on the right hand side of the assignment evaluates to int by default. That's why you need to cast back to a short, because there is no implicit conversion form int to short, for obvious reasons.
Given that the "why int by default" question hasn't been answered ...
First, "default" is not really the right term (although close enough). As noted by VonC, an expression composed of ints and longs will have a long result. And an operation consisting of ints/logs and doubles will have a double result. The compiler promotes the terms of an expression to whatever type provides a greater range and/or precision in the result (floating point types are presumed to have greater range and precision than integral, although you do lose precision converting large longs to double).
One caveat is that this promotion happens only for the terms that need it. So in the following example, the subexpression 5/4 uses only integral values and is performed using integer math, even though the overall expression involves a double. The result isn't what you might expect...
(5/4) * 1000.0
OK, so why are byte and short promoted to int? Without any references to back me up, it's due to practicality: there are a limited number of bytecodes.
"Bytecode," as its name implies, uses a single byte to specify an operation. For example iadd, which adds two ints. Currently, 205 opcodes are defined, and integer math takes 18 for each type (ie, 36 total between integer and long), not counting conversion operators.
If short, and byte each got their own set of opcodes, you'd be at 241, limiting the ability of the JVM to expand. As I said, no references to back me up on this, but I suspect that Gosling et al said "how often do people actually use shorts?" On the other hand, promoting byte to int leads to this not-so-wonderful effect (the expected answer is 96, the actual is -16):
byte x = (byte)0xC0;
System.out.println(x >> 2);
What language are you using?
Many C based languages have a rule that any mathematical expression is performed in size int or larger. Because of this, once you add two shorts the result is of type int. This causes the need for a cast.
Java always uses at least 32 bit values for calculations. This is due to the 32-bit architecture which was common 1995 when java was introduced. The register size in the CPU was 32 bit and the arithmetic logic unit accepted 2 numbers of the length of a cpu register. So the cpus were optimized for such values.
This is the reason why all datatypes which support arithmetic opperations and have less than 32-bits are converted to int (32 bit) as soon as you use them for calculations.
So to sum up it mainly was due to performance issues and is kept nowadays for compatibility.
In java, every numeric expression like:
anyPrimitive zas = 1;
anyPrimitive bar = 3;
?? x = zas + bar
x will always result to be at least an int, or a long if one of the addition elements was a long.
But there's are some quirks tough
byte a = 1; // 1 is an int, but it won't compile if you use a variable
a += 2; // the shortcut works even when 2 is an int
a++; // the post and pre increment operator work
AFAIS, nobody mentions of final usage for that. If you modify your last example and define variables a and b as final
variables, then the compiler is assured that their sum, value 5 , can be assigned to a
variable of type byte, without any loss of precision. In this case, the compiler is good
to assign the sum of a and b to c . Here’s the modified code:
final byte a = 2;
final byte b = 3;
byte c = a + b;
Any data type which is lower than "int" (except Boolean) is implicitly converts to "int".
In your case:
short a = 2;
short b = 3;
short c = a + b;
The result of (a+b) is implicitly converted to an int. And now you are assigning it to "short".So that you are getting the error.
short,byte,char --for all these we will get same error.
I'd like to add something that hasn't been pointed out. Java doesn't take into account the values you have given the variables (2 and 3) in...
short a = 2;
short b = 3;
short c = a + b;
So as far as Java knows, you could done this...
short a = 32767;
short b = 32767;
short c = a + b;
Which would be outside the range of short, it autoboxes the result to an int becuase it's "possible" that the result will be more than a short but not more than an int. Int was chosen as a "default" because basically most people wont be hard coding values above 2,147,483,647 or below -2,147,483,648
If two values have different data types, then java will automatically promote one of the values to the larger of the two data types. In your case, smaller data types such as byte, short and char will be "promoted" to int anytime they are used with a binary arithmetic operator. This is still true if neither operands are an int.
short x = 10;
short y = 20;
short z = x+y // this will be a compiler error. To solve this then casting would be required
short z = (short)(x+y) // this will return 30
short z = (short) x+y //this will return a compiler error
Remember that casting is a unary operator, thus by casting a larger value into a smaller datatype, you are effectively telling the compiler to ignore the default behaviour.

Categories