Can anyone confirm if this is true?
Java will turn a long % int into a long value. However it can never be greater than the modulus to it is always safe to cast it to an int.
long a =
int b =
int c = (int) (a % b); // cast is always safe.
Similarly a long % short will always be safe to cast to a short.
If true, does any one know why Java has a longer type for % than needed?
Additionally, there is a similar case for long & int (if you ignore sign extension)
For most (if not all) arithmetic operations, Java will assume you want the maximum defined precision. Imagine if you did this:
long a = ...;
int b = ...;
long c = a % b + Integer.MAX_VALUE;
If Java automatically down-casted a % b to an int, then the above code would cause an int overflow rather than setting c to a perfectly reasonable long value.
This is the same reason that performing operations with a double and an int will produce a double. It's much safer to up-cast the least-accurate value to a more accurate one. Then if the programmer knows more than the compiler and wants to down-cast, he can do it explicitly.
Update
Also, after thinking more about this, I'm guessing most CPU architectures don't have operations that combine 32-bit and 64-bit values. So the 32-bit value would need to be promoted to a 64-bit value just to use it as an argument to the CPU's mod operation, and the result of that operation would be a 64-bit value natively. A down-cast to an int would add an operation, which has performance implications. Combining that fact with the idea that you might actually want to keep a long value for other operations (as I mention above), it really wouldn't make sense to force the result into an int unless the developer explicitly wants it to be one.
It is always safe! (Math agrees with me.)
The result of a mod operation is always less than the divisor. Since the result of a mod operation is essentially the remainder after performing integer division, you will never have a remainder larger than the divisor.
I suspect the reason for having the operation return a long is because the divisor gets expanded to a long before the operation takes place. This makes a long result possible. (note even though the variable is expanded in memory, its value will not change. An expanded int will never be larger than an int can hold.)
As Marc B alluded to, Java will promote b to a long before actually doing the % operation. This promotion applies to all the arithmetic operations, even << and >> I believe.
In other words, if you have a binary operation and the two arguments don't have the same type, the smaller one will be promoted so that both sides will have the same type.
This is a late party chime-in but the reason is pretty simple:
The bytecode operands do need explicit casts (L2I) and longs need 2 stack positions compared to 1 for int, char, short, byte [casting from byte to int doesn't need a bytecode instruction]. After the mod operation the result takes 2 positions on the top of stack.
edit: Also, I forgot to mention Java doesn't have division/remainder of 64b/32b. There are only 64->64bit operations, i.e. LDIV and LREM.
does any one know why Java has a longer type for % than needed?
I don't know for sure. Maybe to make it work exactly the same way as the other multiplicative operators: * and \. In the JLS The type of a multiplicative expression is the promoted type of its operands. Adding an exception to long % int would be confusing.
Related
I know that numeric literals in Java are by default of the type int.
So the 5 in the following example actually is an int as long as I don't write an 'L' behind it. So why can't I assign the result of a*b back to an int variable, if 5 and 7 are both of the type int?
long a = 5;
int b = 7;
int c = a * b;
I do not understand why Java has problems seeing something like this as long:
long a = 345236577970;
but still performs a typecast if the expression includes a long variable, even though its type is actually int. Super basic beginner question, sorry.
Your reasoning is that 5 and 7 (both int) are assigned to variables which are then multiplied so the result should be an int. The flaw in this reasoning is that your code is not multiplying 5 and 7, but a and b. Once constants are assigned to these variables it's irrelevant what the type of the constant is: the only thing that matters is the type of the variable. In this case the types are long and int so the result is a long.
Simple options to convert to int is to cast or to use Math.toIntExact
Before the computation is done, there's no way to know what the result will be (which seems obvious but sometimes needs to be said out loud). It could be a result that could fit in an int, but it might not be -- it could be a long. So the language is designed to require that the result be of a type that could fit the largest possible range of results.
If you want to stuff the final result back into an int, you can certainly cast it into an int variable, but you do open yourself up to the risk that the result might not fit in there.
Let's say you have two large integers and you want to multiply them.
int a = 150000;
int b = 200000;
Operation 1: [Incorrect] ( Overflows )
long result = a * b;
Operation 2: [Correct]
long result = (long)a*b;
Why is a cast required even though the assignment is to a variable of a type that can accomodate the result?
Yes, a cast is required.
If you don't cast at least one of the int arguments to long, the multiplication will be performed as a 32 bit operation. If multiplication overflows, the value ultimately assigned to result will be incorrect.
As the JLS states (15.7.1):
If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two's-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values.
If either of the operands is long, the multiplication will be performed as a 64 bit operation, and the operation won't overflow.
(There are other ways to cause the operation to be performed using long arithmetic, but a type cast is the most idiomatic.)
In your case, you first cast a into long then you do the multiplication.
You can update the operation to be sure this will result in a long like this long result = 1L * a * b, the numeric result of operation will be a long because it use a long in the beginning (be careful to the operator priority of course).
But this won't work
long result = a * b * 1L
because the integer multiplication will be first done and store in an integer.
See my answer here for a explanation about priority
When you do any arithmetic operation you must know the operators precedence. The assignment operator has the least precedence, hence the result is first computed and then assigned to the given variable, So while computing JAVA allocates the memory bytes of the variable type which has highest byte storage. For E.g.
int*int the computed result will be stored in int
int*float the computed result will be stored in float
float*double the computed result will be stored in double
int* float*double the computed result will be stored in double
So in your example the computed result will be stored in int and then only assignment happens.
This is because a and b in your case are integers, you need to first convert them to long(casting) else you are conflicting. Since long can accommodate your result because it has more bits(i.e 64 bits) then simple int datatype.
I think becuase of the sequence. First multiplication Second assignment.
Cheers.
The range of int type in java is –2,147,483,648 to 2,147,483,647 and the result we get is 30000000000 can't be hold by int so long required.
This question already has answers here:
Why don't Java's +=, -=, *=, /= compound assignment operators require casting?
(11 answers)
Closed 5 years ago.
I know that the compiler does implicit type conversion for integer literals.
For example:
byte b = 2; // implicit type conversion, same as byte b = (byte)2;
The compiler gives me an error if the range overflows:
byte b = 150; // error, it says cannot convert from int to byte
The compiler gives the same error when the variable is passed an expression:
byte a = 3;
byte b = 5;
byte c = 2 + 7; // compiles fine
byte d = 1 + b; // error, it says cannot convert from int to byte
byte e = a + b; // error, it says cannot convert from int to byte
I came to the conclusion that the result of an expression that involves variables cannot be guaranteed. The resulting value can be within or outside the byte range so compiler throws off an error.
What puzzles me is that the compiler does not throw an error when I put it like this:
byte a = 127;
byte b = 5;
byte z = (a+=b); // no error, why ?
Why does it not give me an error?
While decompiling your code will explain what Java is doing, the reason why it's doing it can be generally found in the language specification. But before we go into that, we have to establish a few important concepts:
A literal numeral is always interepreted as an int.
An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1).
A byte can only hold an integer value between -128 and 127, inclusive.
An attempt to assign a literal that is larger than the type that can hold it will result in a compilation error. This is the first scenario you're encountering.
So we're back to this scenario: why would adding two bytes that are clearly more than what a byte can handle not produce a compilation error?
It won't raise a run-time exception because of overflow.
This is the scenario in which two numbers added together suddenly produce a very small number. Due to the small size of byte's range, it's extremely easy to overflow; for example, adding 1 to 127 would do it, resulting in -128.
The chief reason it's going to wrap around is due to the way Java handles primitive value conversion; in this case, we're talking about a narrowing conversion. That is to say, even though the sum produced is larger than byte, the narrowing conversion will cause information to be discarded to allow the data to fit into a byte, as this conversion never causes a run-time exception.
To break down your scenario step by step:
Java adds a = 127 and b = 5 together to produce 132.
Java understands that a and b are of type byte, so the result must also be of type byte.
The integer result of this is still 132, but at this point, Java will perform a cast to narrow the result to within a byte - effectively giving you (byte)(a += b).
Now, both a and z contain the result -124 due to the wrap-around.
The answer is provided by JLS 15.26.2:
For example, the following code is correct:
short x = 3;
x += 4.6;
and results in x having the value 7 because it is equivalent to:
short x = 3;
x = (short)(x + 4.6);
So, as you can see, the latest case actually work because the addition assignment (as any other operator assignment) performs an implicit cast to the left hand type (and in your case a is a byte). Extending, it is equivalent to byte e = (byte)(a + b);, which will compile happily.
I came to the conclusion that the result of an expression that involves variables cannot be guaranteed. The resulting value can be within or outside the byte range so compiler throws off an error.
No, that's not the reason. The compilers of a staticly-typed language work in this way: Any variable must be declared and typed, so even if its value is not known at compile-time, its type is known. The same goes for implicit constants. Based upon this fact, the rules to compute scales are basically these:
Any variable must have the same or higher scale than the expression at its right side.
Any expression has the same scale of the maximum term involved on it.
An explicit cast forces, of corse, the scale of the right-side expression.
(These are in fact a simplified view; actually might be a little more complex).
Apply it to your cases:
byte d = 1 + b
The actual scales are:
byte = int + byte
... (because 1 is considered as an implicit int constant). So, applying the first rule, the variable must have at least int scale.
And in this case:
byte z = (a+=b);
The actual scales are:
byte = byte += byte
... which is OK.
Update
Then, why byte e = a + b produce a compile-time error?
As I said, the actual type rules in java are more complex: While the general rules apply to all types, the primitive byte and short types are more restricted: The compiler assumes that adding/substracting two or more bytes/shorts is risking to cause an overflow (as #Makoto stated), so it requires to be stored as the next type in scale considered "safer": an int.
The basic reason is that the compiler behaves a little differently when constants are involved. All integer literals are treated as int constants (unless they have an L or l at the end). Normally, you can't assign an int to a byte. However, there's a special rule where constants are involved; see JLS 5.2. Basically, in a declaration like byte b = 5;, 5 is an int, but it's legal to do the "narrowing" conversion to byte because 5 is a constant and because it fits into the range of byte. That's why byte b = 5 is allowed and byte b = 130 is not.
However, byte z = (a += b); is a different case. a += b just adds b to a, and returns the new value of a; that value is assigned to a. Since a is a byte, there is no narrowing conversion involved--you're assigning a byte to a byte. (If a were an int, the program would always be illegal.)
And the rules say that a + b (and therefore a = a + b, or a += b) won't overflow. If the result, at runtime, is too large for a byte, the upper bits just get lost--the value wraps around. Also, the compiler will not "value follow" to notice that a + b would be larger than 127; even though we can tell that the value will be larger than 127, the compiler won't keep track of the previous values. As far as it knows, when it sees a += b, it only knows that the program will add b to a when it runs, and it doesn't look at previous declarations to see what the values will be. (A good optimizing compiler might actually do that kind of work. But we're talking about what makes a program legal or not, and the rules about legality don't concern themselves with optimization.)
I have encountered this before in one project and this is what I learned:
unlike c/c++, Java is always use signed primitives. One byte is from -128 to +127 so if you assign anything behind this range it will give you compile error.
If you explicitly convert to byte like (byte) 150 still you won't get what you want (you can check with debugger and see it will convert to something else).
When you use variables like x = a + b because the compiler doesn't know the values at run time and cannot calculate whether -128 <= a+b <= +127 it will give error.
Regarding your question about why compiler doesn't give error on something like a+=b :
I dig into java compiler available from openjdk at
http://hg.openjdk.java.net/jdk9/jdk9/langtools.
I traced the tree processing of operands and came to an interesting expression in one of the compiler files Lower.java which partially responsible for traversing the compiler tree. here is a part of the code that would be interesting (Assignop is for all of the operands like += -= /= ...)
public void visitAssignop(final JCAssignOp tree) {
...
Symbol newOperator = operators.resolveBinary(tree,
newTag,
tree.type,
tree.rhs.type);
JCExpression expr = lhs;
//Interesting part:
if (expr.type != tree.type)
expr = make.TypeCast(tree.type, expr);
JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
opResult.operator = newOperator;:
....
as you can see if the rhs has different type than the lhs, the type cast would take place so even if you declare float or double on the right hand side (a+=2.55) you will get no error because of the type cast.
/*
* Decompiled Result with CFR 0_110.
*/
class Test {
Test() {
}
public static /* varargs */ void main(String ... arrstring) {
int n = 127;
int n2 = 5;
byte by = (byte)(n + n2);
n = by;
byte by2 = by;
}
}
After decompilation of your Code
class Test{
public static void main(String... args){
byte a = 127;
byte b = 5;
byte z = (a+=b); // no error, why ?
}
}
Internally, Java replaced your a+=b operator with (byte)(n+n2) the code.
The expression byte1+byte2 is equivalent to (int)byte1+(int)byte2, and has type int. While the expression x+=y; would generally be equivalent to var1=var1+var2;, such an interpretation would make it impossible to use += with values smaller than int, so the compiler will treat byte1+=byte2 as byte1=(byte)(byte1+byte2);.
Note that Java's type system was designed first and foremost for simplicity, and its rules were chosen to as to make sense in many cases, but because making the rules simple was more important than making them consistently sensible, there are many cases where the type system rules yield nonsensical behavior. One of the more interesting ones is illustrated via:
long l1 = Math.round(16777217L)
long l2 = Math.round(10000000000L)
In the real world, one wouldn't try to round long constants, of course, but the situation might arise if something like:
long distInTicks = Math.round(getDistance() * 2.54);
were changed to eliminate the scale factor [and getDistance() returned long].
What values would you expect l1 and l2 should receive? Can you figure out why they might receive some other value?
HashMap internally has its own static final variables for its working.
static final int DEFAULT_INITIAL_CAPACITY = 16;
Why can't they use byte datatype instead of using int since the value is too small.
They could, but it would be a micro-optimization, and the tradeoff would be less readable and maintainable code (Premature optimization, anyone?).
This is a static final variable, so it's allocated only once per classloader. I'd say we can spare those 3 (I'm guessing here) bytes.
I think this is because the capacity for a Map is expressed in terms of an int. When you try to work with a byte and an int, because of promotion rules, the byte will anyways be converted to an int. The default capacity is expressed in terms of an int to maybe avoid those needless promotions.
Using byte or short for variables and constants instead of int is a premature optimization that has next to no effect.
Most arithmetic and logical instructions of the JVM work only with int, long, float and double, other data types have to be cast to (usually) ints in order for these instructions to be executed on them.
The default type of number literals is int for integral and double for floating point numbers. Using byte, short and float types can thus cause some subtle programming bugs and generally worsens code readability.
A little example from the Java Puzzlers book:
public static void main(String[] args) {
for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
if (b == 0x90)
System.out.print("Joy!");
}
}
This program doesn't print Joy!, because the hex value 0x90 is implicitly promoted to an int with the value 144. Since bytes in Java are signed (which itself is very inconvenient), the variable b is never assigned to this value (Byte.MAX_VALUE = 127) and therefore, the condition is never satisfied.
All in all, the reduction of the memory footprint is simply too small (next to none) to justify such micro-optimisation. Generally, explicit numeric types of different size are not necessary and suitable for higher level programming. I personally think that only case where smaller numeric types are acceptable are byte arrays.
The byte values still taking the same space in the JVM and it will also need to be converted to int to the practical purposes explicitly or implicitly, including array sizes, indexes, etc.
Converting from a byte to an int(as it needs to be anint` in any case) would make the code slower if anything. The cost of memory is pretty trivial in the overall scheme of things.
Given the default could be any int value, I think int makes sense.
A lot of data can be represented as a series of Bytes.
Int is the default data type that most users will use when counting or workign with whole numbers.
the issue with using Byte is that the compiler will not recognize it for type conversion.
anytime you tried
int variablename = bytevariable;
it wouldnt complete the assignment however
double variablename = intVariable;
would work.
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.