I am trying to make general class to calculate Geometric mean using exponential of the arithmetic mean of logarithms , and Arithmetic Mean.
I am looking for some general feedback on how I can improve the structure and efficiency of my code.
package analysis.statistic;
import java.util.Arrays;
public class Mean {
/**
* this function calculate geometric mean using the exponential of the
* arithmetic mean of logarithms
*
* <ul>
* <li>(-1)^m * 1/n-rt(product(numbers)) = (-1)^m exp(1/n
* sum(ln(numbers[i])))
* <li>n : is length of numbers</li>
* <li>m : is number of negative values</li>
* </ul>
*
* @param numbers
* @return geometric mean
* <ul>
* <li>NAN : if numbers array is empty</li>
* <li>0 :if numbers array contain 0 value</li>
* <li>negative value : if numbers array contains odd negative
* values
* <li>positive value : if numbers array contains even negative
* values or just positive values
* </ul>
*
* @throws IllegalArgumentException
* if numbers array are null
*/
public static double geometricMean(int... numbers) {
if (numbers == null) {
throw new IllegalArgumentException("numbers must be not null");
}
if (numbers.length == 0) {
return Double.NaN;
}
int nNegativeValues = 0;
double logarithmSum = 0;
for (int i : numbers) {
if (i > 0) {
logarithmSum += Math.log(i);
} else if (i < 0) {
nNegativeValues += 1;
logarithmSum += Math.log(i * -1);
} else if (i == 0) {
return 0;
}
}
int length = numbers.length;
return expOfArithMeanOfLogs(nNegativeValues, logarithmSum, length);
}
/**
* Works just like {@link Mean#geometricMean(int...)} except the array
* contains long numbers
*/
public static double geometricMean(long... numbers) {
if (numbers == null) {
throw new IllegalArgumentException("numbers must be not null");
}
if (numbers.length == 0) {
return Double.NaN;
}
int nNegativeValues = 0;
double logarithmSum = 0;
for (long i : numbers) {
if (i > 0) {
logarithmSum += Math.log(i);
} else if (i < 0) {
nNegativeValues += 1;
logarithmSum += Math.log(i * -1);
} else if (i == 0) {
return 0;
}
}
return expOfArithMeanOfLogs(nNegativeValues, logarithmSum, numbers.length);
}
/**
* Works just like {@link Mean#Mean#geometricMean(int...)} except the array
* contains double numbers
*/
public static double geometricMean(double... numbers) {
if (numbers == null) {
throw new IllegalArgumentException("numbers must be not null");
}
if (numbers.length == 0) {
return Double.NaN;
}
int nNegativeValues = 0;
double logarithmSum = 0;
for (double i : numbers) {
if (i > 0) {
logarithmSum += Math.log(i);
} else if (i < 0) {
nNegativeValues += 1;
logarithmSum += Math.log(i * -1);
} else if (i == 0) {
return 0;
}
}
return expOfArithMeanOfLogs(nNegativeValues, logarithmSum, numbers.length);
}
/**
* Works just like {@link Mean#geometricMean(int...)} except the array
* contains float numbers
*/
public static double geometricMean(float... numbers) {
if (numbers.length == 0) {
return Double.NaN;
}
int nNegativeValues = 0;
double logarithmSum = 0;
for (float i : numbers) {
if (i > 0) {
logarithmSum += Math.log(i);
} else if (i < 0) {
nNegativeValues += 1;
logarithmSum += Math.log(i * -1);
} else if (i == 0) {
return 0;
}
}
return expOfArithMeanOfLogs(nNegativeValues, logarithmSum, numbers.length);
}
/**
* Return Exponential of the arithmetic mean of logarithms
*
* @param m
* is the number of negative numbers
* @param logarithmSum
* is arithmetic mean of logarithms
* @param n
* numbers of values
* @return exponential of the arithmetic mean of logarithms
*/
private static double expOfArithMeanOfLogs(int m, double logarithmSum, int n) {
double expOfLogarithms = Math.exp(((double) 1 / n) * logarithmSum);
if (m != 0) {
expOfLogarithms = expOfLogarithms * Math.pow(-1, m);
}
return expOfLogarithms;
}
/**
* The mean is the average of the numbers.
* <li>sum(numbers[i])/n</li>
* <li>n : length of array numbers</li>
*
* @param numbers
* integers
* @return average of the numbers
* <ul>
* <li>NAN : if array numbers is empty
* <li>average : if contains numbers
* </ul>
* @throws IllegalArgumentException
* if numbers array is null
*/
public static double arithmeticMean(int... numbers) {
if (numbers == null) {
throw new IllegalArgumentException("numbers must be not null");
}
if (numbers.length == 0) {
return Double.NaN;
}
return (double) Arrays.stream(numbers).parallel().sum() / numbers.length;
}
/**
* Works just like {@link Mean#arithmeticMean(int...)} except the array
* contains double numbers and
*
* @param numbers
* double
*/
public static double arithmeticMean(double... numbers) {
if (numbers == null) {
throw new IllegalArgumentException("numbers must be not null");
}
if (numbers.length == 0) {
return Double.NaN;
}
return (double) Arrays.stream(numbers).parallel().sum() / numbers.length;
}
/**
* Works just like {@link Mean#arithmeticMean(int...)} except the array
* contains long numbers and
*
* @param numbers
* long
*/
public static double arithmeticMean(long... numbers) {
if (numbers == null) {
throw new IllegalArgumentException("numbers must be not null");
}
if (numbers.length == 0) {
return Double.NaN;
}
return (double) Arrays.stream(numbers).parallel().sum() / numbers.length;
}
}
Integer.MIN_VALUE
? \$\endgroup\$Integer.MIN_VALUE
so i rewrite the function like blowpublic static double arithmeticMean(int... numbers) { long tmp = 0; for (int i : numbers) { tmp += i; } return (double) tmp / numbers.length; }
\$\endgroup\$arithmeticMean(int...)
, and the only reason along
overflow cannot occur now is that the size of an array is limited toInteger.MAX_VALUE
, andInteger.MIN_VALUE * Integer.MAX_VALUE > Long.MIN_VALUE
. Anyway, an overflow could also have occurred here withint
values other thanInteger.MIN_VALUE
. I think what @RolandIllig was actually referring to is the fact thatInteger.MIN_VALUE
is the only value where your geometric mean method will fail, because it's the onlyint
value whose additive inverse cannot be represented as anint
. \$\endgroup\$Integer.MIN_VALUE
? \$\endgroup\$Integer.MIN_VALUE
(orLong.MIN_VALUE
, respectively) is really a special case, you could throw anArithmeticException
, thereby making it a part of your method's contract that an overflow can never occur. \$\endgroup\$