Overflow occurs with multiplication - java

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.

Related

Java, Intellij : Replacing numeric overflow expression with one which doesn't overflow

I have a scheduled job running, where I want to calculate time till last 30 days. For that I am getting a warning that numeric overflow detected in expression. How can I safely give 30 days?
#Override
#Scheduled(cron = "0 5 5 * * ?")
public void deleteRepliesAutomatically() {
if(schedulerActive.equals("true")) {
Session session = this.sessionFactory.getCurrentSession();
long now = System.currentTimeMillis();
// Below line gives warning.
long nowMinus1Week = now - (1000 * 60 * 60 * 24 * 30);
Timestamp nowMinus1WeekAsTimeStamp = new Timestamp(nowMinus1Week);
Query query = session.createQuery("from Replies as cm where cm.sortTimeStamp <:limit");
query.setParameter("limit", nowMinus1WeekAsTimeStamp);
List<Replies> repliesList = query.list();
for (Replies replies : repliesList) {
session.delete(replies);
session.flush();
}
}
}
Thank you.
The problem is your expression (1000 * 60 * 60 * 24 * 30) (resulting in 2.592.000.000) is a pure int-computation that is overflowing (Integer.MAX_VALUE is 2.147.483.647).
Just make e.g. the first number a long by adding a L:
(1000L * 60 * 60 * 24 * 30)
This will make the whole computation using the long datatype that is large enough to hold the value.
The answer of piet.t is in correct to fix the issue at hand.
But it would be better maintanable to use TimeUnit enum to calculate from one unit to another.
For example to have milliseconds of one week:
long millis = TimeUnit.DAYS.toMillis(7);
You can also do a import static for DAYS.

Difference between casting to int and intValue() method in Java

I have a long value that needed to be converted to an integer. When I use casting, time to time integer value gives a minus value, which is not expected. But when I use the intValue() method in Long, the expected results comes.
I want to know the difference of casting and using intValue() method
Casting Example
int days = (int) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24));
intValue Example
int days = ((Long) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24))).intValue();
Edit: More Elaborate Example to show minus values without overflow as suggested in comments. Before casting the result is 27. When casting, the value becomes -22. But if intValue method is used, the result is 27.
Code
System.out.println("nextDeliveryDate = " + nextDeliveryDate);
System.out.println("nextDeliveryDate.getTime() = " + nextDeliveryDate.getTime());
System.out.println("expectedDeliveryDate = " + expectedDeliveryDate);
System.out.println("expectedDeliveryDate.getTime() = " + expectedDeliveryDate.getTime());
System.out.println("nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() = " + (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()));
System.out.println("(nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24) = " + (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24));
System.out.println("((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)) = " + ((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)));
System.out.println("((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue() = " + ((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue());
Results
Info: nextDeliveryDate = Thu May 14 00:00:00 IST 2015
Info: nextDeliveryDate.getTime() = 1431541800000
Info: expectedDeliveryDate = Fri Apr 17 00:00:00 IST 2015
Info: expectedDeliveryDate.getTime() = 1429209000000
Info: nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() = 2332800000
Info: (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24) = 27
Info: ((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)) = -22
Info: ((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue() = 27
I don't think your results should be different, because here is what the Long.intValue() method does:
public int intValue() {
return (int)value;
}
Something isn't right with your control flow between those two lines.
You can try this test below:
Calendar now = Calendar.getInstance();
Date fromDate = now.getTime();
now.add(Calendar.YEAR, 10);
Date toDate = now.getTime();
System.out.println("line 0: " + (toDate.getTime() - fromDate.getTime()));
System.out.println("line 1: " + (int)(toDate.getTime() - fromDate.getTime()));
System.out.println("line 2: " + new Long((toDate.getTime() - fromDate.getTime())).intValue());
int days = (int) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24));
System.out.println("line 3: " + days);
days = ((Long) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24))).intValue();
System.out.println("line 4: " + days);
You may be hitting int overflow. If the difference between toDate.getTime() and fromDate.getTime() is greater than 2.147 bilion (i.e. Integer.MAX_VALUE), it won't be possible to express it as an integer and it will just wrap and change to minimum value - e.g. Integer.MAX_VALUE + 100 will give you negative result.
You should do all the operations on longs first until you are sure that it is small enough to be cast to int without overflow. I think both your examples are correct, the first is definitely much clearer than the other.
Also, remember that expressions like 1000 * 60 * 60 * 24 are integers and they may overflow too. For example, the number of miliseconds in a month is 31 * 24 * 3600 * 1000, however written like this it returns -1616567296.
EDIT: Let me explain the output you have attached in your edit :
Info: nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() = 2332800000
Info: (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24) = 27
Info: ((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)) = -22
Info: ((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue() = 27
I will also refer to nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() as x. So we can declare it as long x = 2332800000 (declaring int will give compilation error as it is too large to be hold in 4 bytes).
In the first line, you have x / something, something is an int and x is long, so something will be converted to long, the final result is long.
In the second line, you have ((int) x) / something, so long 2332800000 is cast to integer giving -1962167296 and then you have -1962167296 / something.
In your last line, you have (Long) (x / something) which is effectively the same case as first one.
There is no difference, this code
public static void main(String[] args) {
System.out.println((int) (21470000000l));
System.out.println((int) ((Long)21470000000l).intValue());
}
Has this output :
-4836480
-4836480
Therefore you have different values in your toDate and fromDate.
If the value exceed the MAX of integer, you never get the "expected" result, because it just cant fit in there.
Firstly, to explain a little about the difference between casting to int and IntValue() method in Java.
IntValue() is a method in the Integer class (and other wrapper classes).
What IntValue will do is get the integer and return it as an int type.
Note that int is an primitive datatype and Integer is a class that holds this datatype. It's like a wrapper, because there are data structures that cannot hold primitive datatypes. See this SO question for more info
Basically:
Converting an int to Integer is called boxing.
Converting an Integer to int is called unboxing
As noted in the SO question I linked.
However, as for your example, this is a little different because of the types involved. The difference is that you perform all operations as a Long datatype, which holds a lot more numbers than an int first, for accuracy, then only convert it to an int. So your IntValue() method is from the long datatype, which Java7 docs mention of it's use. Basically it just changes it from a long to an int, which still can cause overflows.
Note that Long is the wrapper class for the primitive datatype long (in which the primitive datatype does not have the IntValue() method)
So the difference in values you get may be because when you did the simple cast from Long -> int primitive datatypes, there wasn't an overflow.
I suggest you test out your code with really large numbers that don't change (unlike date,time which is different every time you fetch it)
Solving the overflow problem
You also might be interested in how to safely cast a long to an int in java as discussed in this SO question as an alternative solution for handling the overflow possibility.
Another way I would suggest is to first cut down the precision (hence you lose precision) into a safe enough value (and precise enough one) before casting it back to an int for use.
Or, use BigIntegers, which are immutable arbitrary-precision integers. see the the documentation on this class and this SO Q&A on how to use it. It is definitely going to add complexity to the code as they are immutable.
This other SO question has good solutions that give nice methods on detecting overflow in ints and longs which I also recommend as well.

Java Mysterious Long Overflow

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.

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.

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