Java Mysterious Long Overflow - java

I'm trying to get a long 2 GB in bytes to test a file size. The result appears to overflow despite being assigned to a Long. This doesn't make any sense to me because in the definition of long, the maximum value is 2^(63)-1 which is much larger than 2 * 1024^3. I have a feeling that it has something to do with a JVM optimization using Integers, but then I'm not sure how to get around this. How should I cast it so it doesn't overflow?
long l = 2 * 1024 * 1024 * 1024;
System.out.println(l);
System.exit(0);

long l = 2 * 1024 * 1024 * 1024;
You are initializing an int here, not a long!
When not suffixed, numeric integral literals are ints by default.
You want to write:
// NOTE THE L SUFFIX
long l = 2L * 1024 * 1024 * 1024;
It is enough for the first literal to be a long for the result of an arithmetic operation to be a long as well.

Append the numbers with L to indicate that they are long values explicitly in the statement:
long l = 2L * 1024L * 1024L * 1024L;
Else, the values in the expression will be treated as integers and then simply assigned to a long.

People have rightly pointed out the problem. Also important here is the evaluation order. In the expression
long l = 2 * 1024 * 1024 * 1024;
2 * 1024 * 1024 * 1024 is evaluated first and then the result is assigned to l. Since the RHS expression is purely and integer, its evaluated as integer (which you saw as overflow) and then assigned to variable on the LHS.
when you change the expression to
2L * 1024 * 1024 * 1024, its correctly evaluated as Long.

Related

Overflow occurs with multiplication

long m = 24 * 60 * 60 * 1000 * 1000;
The above code creates overflow and doesn't print the correct result.
long m2 = 24L * 60 * 60 * 1000 * 1000;
long m3 = 24 * 60 * 60 * 1000 * 1000L;
The above 2 lines print the correct result.
My questions are-
Does it matter to the compiler which I use, m2 or m3?
How does java starts multiplying? Left to right or right to left? Does 24*60 gets computed first or 1000*1000?
In this case -
long m = 24 * 60 * 60 * 1000 * 1000;
The right of the assignment is evaluated first. At right there is no long type data. All are int. So the JVM try to fit the result in an int then the overflow occurred.
And in the second case -
long m2 = 24L * 60 * 60 * 1000 * 1000;
long m3 = 24 * 60 * 60 * 1000 * 1000L;
Here one operand of the multiplication is long. So other are prompted to long automatically. The result is trying to fit to a long. Finally the assignment is done with m2 and m3.
And yes the associativity of multiplication from left to right - means the left operand is taken first. And Based on this fact I think in this scenario we should use -
long m2 = 24L * 60 * 60 * 1000 * 1000;
this statement, since at this statement the promotion to long taken places earlier which reduces the risk of overflow.
I would use the m2 line instead of the m3 line.
Java evaluates the multiplication operator * from left to right, so 24 * 60 is evaluated first.
It just so happens that 24 * 60 * 60 * 1000 (one 1000) doesn't overflow, so that by the time you multiply by 1000L (the second 1000), the product is promoted to long before multiplying, so that overflow doesn't take place.
But as you mentioned in your comments, more factors can cause overflow in the int data type before multiplying the last long number, yielding an incorrect answer. It's better to use a long literal for the first (left-most) number as in m2 to avoid overflow from the start. Alternatively, you can cast the first literal as a long, e.g. (long) 24 * 60 * ....
Since expressions are evaluated from left to right, I would prefer your first solution (m2 = ...).
Reasoning: Let's look at a slightly different example.
long g = Integer.MAX_VALUE * 2 * 2L;
This expression will evaluate to -4 since only the last multiplication casts the first expression to long (which is -2 at this point in time, because both operands are int). If you write
long g = Integer.MAX_VALUE * 2L * 2;
instead, g will hold the expected value of 8589934588 since the first multiplication yields a result of type long.
Multiplying works from left to right, and int * int produces int. So
24 * 60 * 60 * 1000 * 1000
is same as
(((24 * 60)* 60) * 1000) * 1000
which gives us
(((1440)* 60) * 1000) * 1000
(( 86400 ) * 1000) * 1000
( 86400000 ) * 1000
and finally because of integer overflow (since 86400000000 is too big for integer which max value is 2147483647) result will be
500654080
You can eliminate integer overflow by using long as one of arguments (int * long and long * int produces long).
In this case you can do it at start like you did in case of m2: 24L * 60 which will produce long 1440L which again will be multiplied by int 60 producing new long, and so on, producing only long values.
m3 case works here because you are multiplying 86400000 by 1000L which means that you are avoiding integer overflow since result will be long.
Let's multiply more numbers, this line will overflow even there is a 1000L:
long m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L;
While this will give correct result:
long m3 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000;
So we are sure that java start multiplying from left to right and we have to start with Long from the left to prevent overflow.
This is because when we use long as one operand the other all int type operand get prompted to long.
The expression in java evaluated from left to right.

How to avoid overflowing a multiplication of variables?

If I have the following code:
long interval = 0;
interval = ((6000 * 60) * 24) * 30;
It won't run because I would need to make every literal a Long. So this would work:
interval = ((6000L * 60L) * 24L) * 30L;
But what if I'm trying to multiply different variables that are in type char? Say I have:
char a, b, c, d;
And I give each of these chars a number value so I try:
interval = a * b * c * d;
If this overflows, I can't just put the L because that would call different variables.
interval = aL * bL * cL * dL;
I have tried converting each of these chars into a long before hand but the product still returns a negative number.
You just have to cast (any) one of the variables to long in order for long multiplication to take place :
interval = (long)a * b * c * d;
interval = ((6000L * 60L) * 24L) * 30L;
This code seems to be calculating the number of milliseconds in 30 days.
Well, then, use what the JDK has to offer:
interval = TimeUnit.DAYS.toMillis(30L);
javadoc for TimeUnit
When applying the multiplicative operator to its operands,
Binary numeric promotion is performed on the operands (§5.6.2).
That is, for this case,
Otherwise, if either operand is of type long, the other is converted to long.
So, really, all you need is to have one long value at the beginning of the multiplication. You can achieve this in a few ways. Either use a cast as demonstrated by Eran. Or use a long literal in the expression
char a, b, c, d;
...
interval = 1L * a * b * c * d;
// (......) result is a long value
By beginning of the multiplication, I'm referring to the fact that multiplicative operator is left associative. In your example, if the result of the first application of * is a long value, it will propagate to the next *.

why long COOKIE_TIMEOUT = 1000 * 60 * 60 * 24 * 30 return negative? [duplicate]

This question already has answers here:
Multiplication operation in Java is resulting in negative value
(4 answers)
Closed 8 years ago.
final long COOKIE_TIMEOUT = 1000 * 60 * 60 * 24 * 30;
Output: -1702967296
Someone told me to put L after 1000 & it works
final long COOKIE_TIMEOUT = 1000L * 60 * 60 * 24 * 30;
Output: 2592000000
Why does that happen?
Integer overflow, put 1000L, this will force long conversion
UPDATE
Slightly longer explanation:
If you just do 1000*10 for example, java will see them as integers.
In your original code, you were doing an integer calculation which overflowed, then cast the overflowed value to long.
However if you put L after the first number, java will see them as longs (left-most operand defines the granularity) and you won't get an overflow.
As another example take this code:
double a = 5 / 2;
double b = 5d / 2;
System.out.println(a + " != " + b);
This will print out:
2.0 != 2.5
Why? When calculating a, java sees 5 and 2 as integers and does an integer division, then casts the result to a double. When calculating b you tell java that 5 is actually a double at which point it performs a double division.
Although COOKIE_TIMEOUT is long the right-hand expression consists of integers, so its type is int. The result is greater than Integer.MAX_VALUE that causes overflow. When at least one operand in your expression belongs to higher type (e.g. long) whole expression becomes long and overflow does not happen.
This is what you did in your second example when you added L modifier after one of the numeric constants. This constant became long, so the expression became long too.
This behavior is due to the type of the expression selected by the Java compiler. In this case it looks something like so:
int * int -> int (which overflows here during the multiplication)
long * long -> long
long * int = long * long (by promotion) -> long
int * long = long (by promotion) * long -> long
This promotion happens pretty much universally for the math operators: the widest/largest type is used, with the smaller type being promoted and the x op x -> x expression being applied (classically, integer vs. floating division).
The L results in a long value and thus the multiplication selected is long * long (by promotion) -> long, which is free from the immediate overflow discovered. The long expression result type propagates to all the other multiplications.
Bonus points: it would still fail (overflow) if written as 1000 * 60 * 60 * 24 * 30 * 1L, why?
It is greatter than Integer.MAX_VALUE which is 2147483647
By default all numeric litaral are considered as Integer. to define a Long numeric value you have to add L or 'l' with the number.
The reason of that behavior is integer overflow.
Your first statement can be understand like this:
long time = 1000 * 60 * 60 * 24 * 30;
is the same as
int time = 1000 * 60 * 60 * 24 * 30;
long timel = time;
First you compute the expression, then you assign to long type;
When you put suffix L to literal you define it as long type.
JSL 3.10.1. Integer Literals
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).
long time = 1000L * ( 60 * 60 * 24 * 30);
can be written also as
long time = ((long) 1000) * ( 60 * 60 * 24 * 30);
More about Primitive Data Types
It is causing for Integer overflow(Max value upto 2147483647).
You can postfix L at the end of the any numeric value.
Like 1000L
Then it forcely converts into Long type
What happens here is that the right hand side is evaluated before the assignment to the left hand side. Since you are multiplying several ints, the resulting type will be int. Then, after evaluating the right hand side, it will see that it is supposed to assign this value to a long, and do the casting automatically.
So you have:
Evaluated right hand side as int: 1000 * 60 * 60 * 24 * 30 = 2,592,000,000.
The maximum value of an int is: 2,147,483,647.
So you have an overflow, which makes the int negative. This is then assigned to a long, still negative.
When you specify one of the operands on the right hand side to be long, then the expression will be evaluated has a long, which has a much larger maximum value.
Every number in the formula is an Integer, hence Java will perform all calculations in Integer and store the result temporarily as Integer. However the result exceeds Integer Max range (overflow), so it becomes negative.
1000 * 60 * 60 * 24 * 30 = 2592000000 (exceeds Integer.MAX_VALUE)
Only when Java needs to assign it to the Long variable Java will cast it into a Long. Since the result is already wrong result (due to overflow) then the Long variable will be assigned with the wrong result.
However if you already declare the 1000 as Long (1000L), then the remaining calculations will be done as Long instead of Integer.

Java long assignment confusing

Why does this java code
long a4 = 1L;
long a3 = 1;
long a2 = 100L * 1024 * 1024 * 1024;
long a1 = 100 * 1024 * 1024 * 1024;
System.out.println(a4);
System.out.println(a3);
System.out.println(a2);
System.out.println(a1);
when run, output
1
1
107374182400
0
instead of the expected
1
1
107374182400
107374182400
output?
long a2 = 100L * 1024 * 1024 * 1024;
In this operation however at least one operand is long. hence the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. The other non-long operand are
widened to type long by numeric promotion and resulted value gets stored to to variable a2.
long a1 = 100 * 1024 * 1024 * 1024;
The constant expression of plain integer, the result of the expression was computed as a type int. The computed value however too large to fit in an integer and hence overflowed, resulting in 0 and gets stored to a1 variable.
Edit: As is asked in the following comment:
Why doesn't it go negative?
Because while in integer computation the second computation is equivalent to 25 * 2^32 where ^ has the power meaning and 2^32 integer value is 0. However, to explain why it's value is 0: In binary:
100 * 1024 * 1024 * 1024 == 25 * 2^32;
Integer.MAX_VALUE = 2 ^ 31 -1 = 0 11111111 11111111 11111111 1111111
Integer.MAX_VALUE + 1 = 2 ^ 31 = 1 00000000 00000000 00000000 0000000
2 ^ 31 is a negative integer(-2147483648) as the sign bit is 1 And hence 2 ^ 32 is just a multiplication of 2 to 2 ^ 31: a left shift and the sign bit will become 0 and hence the result is 0.
Check out the java language specification: 4.2.2: Integer operation for details.
107374182400 is exactly 25 times the full range of an integer (2^32), which means that if you try to fit it into an integer it will overflow. And because it would fit exactly 25 times it ends up precisely on 0 (this is a coincidence and other huge multiplications may end up either positive or negative). And you are using an integer right up to the point you cast to long
long a1 = 100 * 1024 * 1024 * 1024;
is equivalent to
int temp = 100 * 1024 * 1024 * 1024;
long a1 = (long)temp;
If you put a single long in the expression, it is forced to use long maths not integer maths which removes the problem
It might be that the expression on the right of a1 is first calculated as an int and later on converted to long. If it equals 0 as an int it'll stay 0 as a long
As per the documentation of Lexical Literals it is mentioned that,
The type of a literal is determined as follows:
- The type of an integer literal (§3.10.1) that ends with L or l is long (§4.2.1).
- The type of any other integer literal is int (§4.2.1).
Thus your expression, 100 * 1024 * 1024 * 1024 is evaluated as int primitive data type because l or L is not mentioned in any numeric value. and the result is 107374182400 i.e. in Binary it is 1 1001 0000 0000 0000 0000 0000 0000 0000 0000 and int is 32-bit so low 32-bit are taken as mentioned in Example 4.2.2-1. Integer Operations which results to 0
It is also mentioned in same documentation that,
If an integer operator other than a shift operator has at least one operand of type long, then
the operation is carried out using 64-bit precision, and the result of the numerical operator is of
type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion
It means any value in expression contains l or L then all the int values will be expanded to 64 bit.
EDIT In the comment it is also asked
Why doesn't it go negative?
I think it also answers the above question
long a4 = 1L; //No problem in this
long a3 = 1; //here left side primitive is considered as integer and at the time of assignment it will be casted to long so again result is as expected
long a2 = 100L * 1024 * 1024 * 1024; (here you have used 100L so others will be type casted to Long so expected output)
long a1 = 100 * 1024 * 1024 * 1024; (as by default any primitive digit is considered as int in java, it will consider this as integer multiplication so it goes out of range and results in 0)
Here's what you did :
You assigned 100 * 1024 * 1024 * 1024
to a long data type but you didn' said that 100 * 1024 * 1024 * 1024 is a long value
By default java compiler thinks that its an integer. Since integer cannot hold that much value, it will show wrong result. Hope it helps !
reason is integer overflow
as output of 100 * 1024 * 1024 * 1024; is an integer(int) not long
and in long a2 = 100L * 1024 * 1024 * 1024; you are specifying that one of the value is long (here 100L) and multiplication with that value results in long value which gets correctly stored in a2
In Java, if you have int * int, it will compute the output as an int. It only gives the result as a long if you do int * long.
In your case, the 100 * 1024 * 1024 * 1024 has a result that overflows int.
So, adding a "L" makes the operand to be a long, and the computation stores the values in long. And of course, no overflow occurs and a correct result can be outputed (i.e. a2).
Number 3 worked because you specified a long type which is 100L. Thats why it is a long multiplication and could be stored. On the other hand number 4 is an integer multiplication with max value 2^32-1 thats why you got an overflow and the zero default valued appeared.

Android / Java: long gets negative without exceeding max_value

I'm trying to do some basic calculation stuff in my android app to compare a Date.getTime() value with some calculated stuff.
The calculation I do during a database query is:
long minus = pauseDays * 24 * 60 * 60 * 1000;
So basically I calculate the millisecond-value of pauseDays. If pauseDays gets bigger (I'm talking about 90 days or so), something strange happens. The result of the calculation is a negative number.
The weird thing is, that the result should be 7776000000, so it should be way smaller than Long.MAX_VALUE. Could anybody explain to me why I get a negative number here?
The reason is probably because pauseDays is an int type, right? Then you are multiplying it by another bunch of ints, then converting it to long.
Consider this:
public class Main {
public static void main(String[] args) {
int pauseDays = 90;
long minus = pauseDays * 24 * 60 * 60 * 1000;
System.out.println(minus);
long pauseDaysL = 90L;
long minusL = pauseDaysL * 24L * 60L * 60L * 1000L;
System.out.println(minusL);
}
}
The output of this is:
-813934592
7776000000
Notice that the first long minus uses integers to generate its value. The second long minusL uses all long integer values.

Categories

Resources