Sunday, July 18, 2010

The Long Face

Recently, I was trying to test out if the number signifying a Terabyte could fit into an integer. Now, at times like these, I do the odd back of the envelope calculations, but when it comes to an customer reported issues, I generally ensure that I write a couple of lines of code to ensure that I have come to the correct conclusion. Well, it hardly takes a couple of minutes to write a piece of code as small as this. So I went ahead. This is the code I wrote...

Before reading on, try figuring out the ouput of the listing below.
public class TestLimits
{
    public static void main(String[] args)
    {
        int TERABYTE = 1024 * //KB
                                    1024 * //MB
                                    1024 * //GB
                                    1024; //TB
        System.out.println(TERABYTE > Integer.MAX_VALUE);
        System.out.println(TERABYTE);
    }
}
Unfortunately, this sent me to the wrong conclusion. I soon realized that I made a simple mistake, I missed how Java operations works. First off, the since the I marked TERABYTE as an Integer object, so there is no point of the comparison after the assignment. But then I was counting on some kind of OverflowException anyway. Next off, I didn't realize that an OverflowException won't happen here, because when an overflow does happen, the resultant will just become 0.

So, how to overcome this and make this program work as expected. Simple, instead of using an int, use a long for the variable TERABYTE. Before reading on, try doing it. So, what happened, what was the output, let me guess (OK, that may not be fair cause I have already done it). The output was false and zero. What the hell happened!!!

What went wrong is that there was a numeric overflow in the expression. Why, you ask? Java treats everything that looks like an Integer (as defined mathematically), as an Integer, as long as it can fit in the 4 bytes allocated to it, unless you specifically ask Java to treat it otherwise. This is done by adding characters to the number like L for long and F for float. So even if the result is assigned to long, the result before assignment is still an integer. Only during the actual assignment, does the type conversion really happen. So we didn't really change anything.

Let's give this another shot. This time I am going to ask JVM to treat these numbers as long and not an integer. The expression now looks like,


        long TERABYTE = 1024L * //KB
                                       1024L * //MB
                                       1024L * //GB
                                       1024L; //TB

This should set things straight.