package com.mindprod.example;

/**
 * HowToProcess to compute the Average of Two Numbers. Based on Joshua Bloch's blog.
 * http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html This little program demonstrate
 * how even simple computing techniques sometimes give incorrect answers.
 * <p/>
 * composed with IntelliJ IDEA
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0, 2007-07-08
 */
public final class TestAverage
    {
    // -------------------------- STATIC METHODS --------------------------

    /**
     * Compute average of two ints four different ways. Attempts to compute the average of low and high truncated down
     * to the nearest integer.
     *
     * @param low         low value.
     * @param high        high value.
     * @param description description of what is unusual about this pair.
     */
    private static void trial( int low, int high, String description )
        {
        int correct = ( int ) ( ( ( long ) low + ( long ) high ) / 2 );

        // fails if low + high > Integer.MAX_VALUE.
        int average1 = ( low + high ) / 2;

        // fails if low > high, or if both low and high are negative,
        int average2 = low + ( ( high - low ) / 2 );

        // fails if low and high are negative.
        int average3 = ( low + high ) >>> 1;

        System.out
                .printf( "%10d   %10d   %10d   %10d   %10d   %10d   %s%n",
                        low,
                        high,
                        correct,
                        average1,
                        average2,
                        average3,
                        description );
        }

    // --------------------------- main() method ---------------------------

    /**
     * main program to test average-calculating code.
     *
     * @param args command line not used.
     */
    public static void main( String[] args )
        {
        System.out
                .println(
                        "       low |       high |       long | simple div |   +1/2diff |      shift | " );

        trial( 2, 5, "ordinary case" );
        trial( -8, -5, "both negative" );
        trial( -8, 11, "one negative, one positive " );
        trial( 1000, 11, "low > high" );
        trial( Integer.MAX_VALUE - 10,
                Integer.MAX_VALUE - 9,
                "sum greater than Integer.MAX_VALUE" );
        trial( Integer.MAX_VALUE - 2,
                Integer.MAX_VALUE - 9,
                "sum greater than Integer.MAX_VALUE, low > high" );
        }

    // Here is what the output looks like:
    // * marks an incorrect answer for the average.
    //       low |       high |       long | simple div |   +1/2diff |      shift |
    //         2            5            3            3            3            3   ordinary case
    //        -8           -5           -6           -6           -7*  2147483641*  both negative
    //        -8           11            1            1            1            1   one negative, one positive
    //      1000           11          505          505          506*         505   low > high
    //2147483637   2147483638   2147483637          -10*  2147483637   2147483637   sum greater than Integer.MAX_VALUE
    //2147483645   2147483638   2147483641           -6*  2147483642*  2147483641   sum greater than Integer.MAX_VALUE, low > high
    }