/*
 * [TestAverage.java]
 *
 * Summary: Compute average of two ints four different ways.
 *
 * Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.8+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2007-07-08
 */
package com.mindprod.example;

import static java.lang.System.*;

/**
 * Compute average of two ints four different ways.
 * <p/>
 * 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.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2007-07-08
 * @since 2007-07-08
 */
public final class TestAverage
    {
    /**
     * 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;
        out.printf( "%10d   %10d   %10d   %10d   %10d   %10d   %s%n",
                low,
                high,
                correct,
                average1,
                average2,
                average3,
                description );
        }

    /**
     * main program to test average-calculating code.
     *
     * @param args command line not used.
     */
    public static void main( String[] args )
        {
        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
    }