Minima and maxima

Java provides a set of handy constants indicating the lower and upper bounds of its primitive data types. For example, Integer.MIN_VALUE = -2147483648. Similarly, Double.MAX_VALUE will give you the maximum size a double can have.

A frequent use for these constants is in searching for the smallest or largest value in an array:

public int max(int[] numbers)
{
    int max = Integer.MIN_VALUE;
    for(int number : numbers)
        if (number > max)
            max = number;
    return max;
}

The first value in this array will either be MIN_VALUE itself, or greater than MIN_VALUE and so the result is guaranteed to be correct for all non-empty arrays. For empty arrays the result is undefined, so you might want to add a check to the method

if (numbers.length == 0)
        throw new IllegalArgumentException("Numbers array can not be empty");

One slight problem

In many ways, these constants are the programming equivalent of plus and minus infinity and it is often safe to use them as such. There are, however, some quirks that make them a little more difficult to work with. Consider the following code

System.out.println(Integer.MIN_VALUE);
System.out.println(-Integer.MIN_VALUE);
System.out.println(Integer.MAX_VALUE);
System.out.println(-Integer.MAX_VALUE);

Which returns

-2147483648
-2147483648
2147483647
-2147483647

Why? Well MIN_VALUE = -2147483648, so that one's correct. But if you negate that value you get 2147483647+1, which overflows right back into MIN_VALUE. As a result of this, you need to be very careful when passing these values as arguments to a function: if you suspect the function is going to negate the value, you might want to pass -Integer.MAX_VALUE instead of Integer.MIN_VALUE.

A real world example

One situation where this problem arises is MINIMAX using alpha-beta pruning. Wikipedia gives the following pseudo-code (translated from pseudo-pascal into pseudo-java for your benefit :)

public static method alphaBeta(Node node, int depth, int a, int b)
{
    if(depth = 0 || node is a terminal node)
        return the heuristic value of node
    for(Node child : node.children)
    {
        a = Math.max(a, -alphaBeta(child, depth-1, -b, -a));  
        if b <= a
            break;
    }
    return a;
}

public static void main(String[] args)
{
    // Create nodes
    // ...
    // Initial call
    alphaBeta(origin, depth, -infinity, +infinity);
}

This function is called on a graph node that makes recursive calls to its child nodes. Making the initial call as

alphaBeta(origin, depth, Integer.MIN_VALUE, Integer.MAX_VALUE);

will cause the first recursive call to invert MAX_VALUE into -MAX_VALUE, and MIN_VALUE into MIN_VALUE: not the desired result! On the other hand

alphaBeta(origin, depth, -Integer.MAX_VALUE, Integer.MAX_VALUE);

Will lead to the expected behaviour.

Confusing? I sure think so! If you know a clever way around these situations, please let me know in the comment box below.

Apr 18th, 2010

Comments

No comments yet! Feel free to post some using the form below.

Post your comments here

If you wish to add code to your comment you can use code tags, like this: <code class="php">yourCodeHere</code>.
Quite a large number of languages are supported, although I can't guarantee it'll be pretty. Inside the code tags you can use any characters except for the string "</code>".