/*
* [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
}
}