## average

in java

### Source Code

``````package average;

import java.util.*;
import java.util.stream.DoubleStream;

/**
* @author Joshua Moody (joshimoo@hotmail.de)
*/
public final class Average {
/**
* Don't let anyone instantiate this class.
*/
private Average() {}

/**
* calculate a regular arithmetic mean average
* @throws NoSuchElementException if the array is empty
*/
public static double arithmeticMean(double... numbers) {
assert numbers != null && numbers.length > 0;
return DoubleStream.of(numbers).average().getAsDouble();
}

/**
* calculates a weighted mean average
* numbers and weights need to have the same count
*/
public static double weightedMean(double[] numbers, double[] weights) {
assert numbers.length == weights.length;
double weightedSum = 0;
for (int i = 0; i < numbers.length; i++) {
weightedSum += numbers[i] * weights[i];
}

return weightedSum / DoubleStream.of(weights).sum();
}

/**
* calculates the harmonic mean average
* according to this formula: n/(1/x1 + 1/x2 + ... + 1/xn)
*/
public static double harmonicMean(double... numbers) {
return numbers.length / DoubleStream.of(numbers).map(x -> 1.0 / x).sum();
}

/**
* calculates the contra harmonic mean average
* according to this formula: (x1^2 + x2^2 + ... + xn^2)/(x1 + x2 + ... + xn)
*/
public static double contraHarmonicMean(double... numbers) {
return DoubleStream.of(numbers).map(x -> Math.pow(x, 2.0)).sum() / DoubleStream.of(numbers).sum();
}

/**
* calculates the geometric mean average
* for small amount of numbers according to this formula: (x1*x2*...xn) ^ (1/n)
* for large amount of numbers, by summing the logarithms of each x
*/
public static double geometricMean(double... numbers) {
// TODO: For large numbers, consider summing the logarithms of each x
// (x1*x2*...xn) ^ (1/n)
return Math.pow(DoubleStream.of(numbers).reduce(1.0, (a, x) -> (a * x)), 1.0d / numbers.length);
}

/**
* calculates the quadratic mean average
* according to  this formula: sqrt( (x1)^2+(x2)^2+(x3)^2+...+(xn)^2 /n )
*/
public static double quadraticMean(double... numbers) {
return generalizedMean(numbers, 2.0);
}

/**
* calculates a generalized mean average
* according to this formula: y-root( (x1)^y+(x2)^y+(x3)^y+...+(xn)^y / n )
*/
public static double generalizedMean(double[] numbers, double power) {
return Math.pow(arithmeticMean(DoubleStream.of(numbers).map(x -> Math.pow(x, power)).toArray()), 1.0 / power);
}

/**
* Get the mid value beetwen min and max
*/
public static double midrange(double... numbers) {
DoubleSummaryStatistics stat = DoubleStream.of(numbers).summaryStatistics();
return arithmeticMean(stat.getMin(), stat.getMax());
}

/**
* calculates the median average for sorted list of numbers
* @param numbers needs to be sorted
* @return mean average of left and right for even numbers, else mid element
*/
public static double median(double... numbers) {
if (numbers.length % 2 == 0) {
double left = numbers[(numbers.length / 2) - 1];
double right = numbers[numbers.length / 2];
return arithmeticMean(left, right);
} else {
double mid = numbers[((numbers.length + 1) / 2) - 1];
return mid;
}
}

/**
* calculates the mode average
* which returns the element, with highest occurrence count
*/
public static double mode(double... numbers) {
// Stupid Type System, all this boxing :(
Map<Double, Integer> frequencies = new HashMap<>();

for(double key : numbers) {
frequencies.put(key, frequencies.getOrDefault(key, 0) + 1);
}

Double maxElement = numbers[0];
for (Map.Entry<Double, Integer> element : frequencies.entrySet()) {
if(element.getValue() > frequencies.get(maxElement)) {
maxElement = element.getKey();
}
}

return maxElement;
}

}
``````
``````package average;

import org.junit.Test;
import java.util.stream.DoubleStream;
import static org.junit.Assert.*;

/**
* @author Joshua Moody (joshimoo@hotmail.de)
*/
public class AverageTest {
private static final double DELTA = 0.01;

@Test
public void testAverageInequality() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5 };

/**
* Mean Inequalities:
* Some means are in a constant relationship to one another.
* If we denote the arithmentic mean of x and y by A,
* their geometric mean by G,
* their harmonic mean by H,
* their root mean square (quadratic mean) by R,
* and their contraharmonic mean by C,
*
* then the following chain of inequalities is always true
* C >= R >= A >= G >= H
*/

double contraHarmonic = Average.contraHarmonicMean(numbers);
double arithmetic = Average.arithmeticMean(numbers);
double geometric = Average.geometricMean(numbers);
double harmonic = Average.harmonicMean(numbers);
assertTrue("Your Average inequalities are not correct", (contraHarmonic >= quadratic) && (quadratic >= arithmetic) && (arithmetic >= geometric) && (geometric >= harmonic));
}

@Test
public void testArithmeticMean() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = DoubleStream.of(numbers).average().getAsDouble();
assertEquals(expected, Average.arithmeticMean(numbers), DELTA);
}

@Test
public void testWeightedMean() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double[] weights = new double[] { 1, 1, 1, 1, 1 };
double expected = DoubleStream.of(numbers).average().getAsDouble();
assertEquals(expected, Average.weightedMean(numbers, weights), DELTA);
}

@Test
public void testHarmonicMean() throws Exception {
// n/(1/x1 + 1/x2 + ... + 1/xn)
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = numbers.length / DoubleStream.of(numbers).map(x -> 1.0 / x).sum();
assertEquals(expected, Average.harmonicMean(numbers), DELTA);
}

@Test
public void testContraHarmonicMean() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = DoubleStream.of(numbers).map(x -> Math.pow(x, 2.0)).sum() / DoubleStream.of(numbers).sum();
assertEquals(expected, Average.contraHarmonicMean(numbers), DELTA);
}

@Test
public void testGeometricMean() throws Exception {
// (x1*x2*...xn) ^ (1/n)
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = Math.pow((numbers[0] * numbers[1] * numbers[2] * numbers[3] * numbers[4]), 1.0 / numbers.length);
assertEquals(expected, Average.geometricMean(numbers), DELTA);
}

@Test
public void testQuadraticMean() throws Exception {
// sqrt((x1)^2+(x2)^2+(x3)^2+...+(xn)^2 /n)
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = Math.sqrt(DoubleStream.of(numbers).map(x -> Math.pow(x, 2)).sum() / numbers.length);
}

@Test
public void testGeneralizedMean() throws Exception {
// y-root((x1)^y+(x2)^y+(x3)^y+...+(xn)^y / n)
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double power = 4;
double expected = Math.pow((DoubleStream.of(numbers).map(x -> Math.pow(x, 4)).sum() / numbers.length), 1.0 / power);
assertEquals(expected, Average.generalizedMean(numbers, power), DELTA);
}

@Test
public void testMidrange() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = (numbers[0] + numbers[numbers.length - 1]) / 2.0;
assertEquals(expected, Average.midrange(numbers), DELTA);
}

@Test
public void testMedianEven() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5, 6};
double expected = (numbers[(numbers.length / 2) - 1] + numbers[numbers.length / 2]) / 2.0;
assertEquals(expected, Average.median(numbers), DELTA);
}

@Test
public void testMedianOdd() throws Exception {
double[] numbers = new double[] { 1, 2, 3, 4, 5 };
double expected = numbers[((int) Math.floor(numbers.length / 2))];
assertEquals(expected, Average.median(numbers), DELTA);
}

@Test
public void testMode() throws Exception {
// frequency based average
double[] numbers = new double[] { 1, 2, 3, 3, 3, 4, 5 };
double expected = 3;
assertEquals(expected, Average.mode(numbers), DELTA);
}
}``````