/* * [TestSummary.java] * * Summary: Demonstrate various ways of summarising/averaging a list of doubles with a single number. * * 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 2009-09-02 */ package com.mindprod.example; import static java.lang.System.*; /** * Demonstrate various ways of summarising/averaging a list of doubles with a single number. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2009-09-02 * @since 2009-09-02 */ public final class TestSummary { /** * test numbers to average */ private static final double[] TEST_DATA = { 223.0, 223.8, 221.8, 227.3, 223.6, 224.4, 222.6, 227.9, 227.2 }; /** * test weights, need not be normalised. Must be one for each element in TEST_DATA. */ private static final double[] TEST_WEIGHTS = { .10, .5, .20, .5, .5, .5, .5, .3, .4 }; /** * Compute ordinary arithmetic average * * @param numbers array of doubles * * @return the ordinary arithmetic average or NaN for an empty array. * @throws NullPointerException if numbers is null */ @SuppressWarnings( { "WeakerAccess" } ) public static double arithmeticMean( double... numbers ) { if ( numbers.length == 0 ) { return Double.NaN; } double sum = 0; for ( double number : numbers ) { sum += number; } return sum / numbers.length; } /** * Compute geometric mean, nth root of the product of all the numbers. * * @param numbers array of doubles * * @return the geometric mean or NaN for an empty array. * @throws NullPointerException if numbers is null * @see Wikipedia on geometric mean */ @SuppressWarnings( { "WeakerAccess" } ) public static double geometricMean( double... numbers ) { if ( numbers.length == 0 ) { return Double.NaN; } double sum = 0; for ( double number : numbers ) { // Math.log is base e, natural log, ln sum += Math.log( number ); } return Math.exp( sum / numbers.length ); // note divide BEFORE taking exp } /** * Compute harmonic mean, the reciprocal of the arithmetic mean of the reciprocals. * * @param numbers array of doubles * * @return the harmonic mean or NaN for an empty array. * @throws NullPointerException if numbers is null * @see Wikipedia on harmonic mean */ @SuppressWarnings( { "WeakerAccess" } ) public static double harmonicMean( double... numbers ) { if ( numbers.length == 0 ) { return Double.NaN; } double sum = 0; for ( double number : numbers ) { // Math.log is base e, natural log, ln sum += 1 / number; } return 1 / ( sum / numbers.length ); // note divide BEFORE taking reciprocal } /** * main program to test/demonstrate average/summarising methods. * * @param args command line not used. */ public static void main( String[] args ) { out.println( minimum( TEST_DATA ) ); // 221.8 out.println( powerMean( -50, TEST_DATA ) ); // 224.1488630356682 out.println( harmonicMean( TEST_DATA ) ); // 224.60200930223507 out.println( powerMean( -1, TEST_DATA ) ); // 224.60200930223507 (same as harmonicMean) out.println( powerMean( -.5, TEST_DATA ) ); // 224.60705292339645 out.println( geometricMean( TEST_DATA ) ); // 224.6121030029759 out.println( powerMean( .5, TEST_DATA ) ); // 224.61715946234176 out.println( powerMean( .9, TEST_DATA ) ); // 224.6212091700313 out.println( arithmeticMean( TEST_DATA ) ); // 224.62222222222223 out.println( powerMean( 1, TEST_DATA ) ); // 224.62222222222223 (same as arithmeticMean) out.println( rmsMean( TEST_DATA ) ); // 224.6323663232883 out.println( powerMean( 2, TEST_DATA ) ); // 224.6323663232883 (same as rmsMean) out.println( weightedMean( TEST_DATA, TEST_WEIGHTS ) ); // 224.78857142857146 out.println( powerMean( 50, TEST_DATA ) ); // 225.1341964090114 out.println( maximum( TEST_DATA ) ); // 227.9 out.println( arithmeticMean( Double.MAX_VALUE, Double.MAX_VALUE / 2 ) ); // Infinity (sum calculation overflows) } /** * Find the biggest number * * @param numbers array of doubles * * @return the maximum value or NaN for an empty array. * @throws NullPointerException if numbers is null */ @SuppressWarnings( { "WeakerAccess" } ) public static double maximum( double... numbers ) { if ( numbers.length == 0 ) { return Double.NaN; } double max = numbers[ 0 ]; for ( double number : numbers ) { if ( number > max ) { max = number; } } return max; } /** * Find the smallest number * * @param numbers array of doubles * * @return the minimum value or NaN for an empty array. * @throws NullPointerException if numbers is null */ @SuppressWarnings( { "WeakerAccess" } ) public static double minimum( double... numbers ) { if ( numbers.length == 0 ) { return Double.NaN; } double min = numbers[ 0 ]; for ( int i = 1; i < numbers.length; i++ ) { if ( numbers[ i ] < min ) { min = numbers[ i ]; } } return min; } /** * Compute power average, a generalisation of rms average. Aka Hölder or generalised mean. * * @param power, need not be integral. Must not be 0. power=2 is same as rms average. * @param numbers array of doubles * * @return the generalised power mean or NaN for an empty array. * @throws NullPointerException if numbers is null * @see Wikipedia on rms mean */ @SuppressWarnings( { "WeakerAccess" } ) public static double rmsMean( double... numbers ) { if ( numbers.length == 0 ) { return Double.NaN; } double sum = 0; for ( double number : numbers ) { sum += number * number; } return Math.sqrt( sum / numbers.length ); // note divide BEFORE taking sqrt } /** * Compute ordinary arithmetic average, with weights on each value. * If all weights are equal e.g. 1, this is the same as an arithmetic mean. * * @param numbers array of doubles * @param weights array of weights. Need non be normalised (i.e. add up to 1 or 100). * * @return the weighted arithmetic average or NaN for an empty array. * @throws NullPointerException if numbers or weights is null */ @SuppressWarnings( { "WeakerAccess" } ) public static double weightedMean( double[] numbers, double[] weights ) { assert numbers.length == weights.length : "Must have one weight per number"; if ( numbers.length == 0 ) { return Double.NaN; } double sum = 0; double weightSum = 0; for ( int i = 0; i < numbers.length; i++ ) { sum += numbers[ i ] * weights[ i ]; weightSum += weights[ i ]; } return sum / weightSum; // We do not also divide by numbers.length } }