/***************************************************************************
* Copyright (C) 2012 by H-Store Project *
* Brown University *
* Massachusetts Institute of Technology *
* Yale University *
* *
* http://hstore.cs.brown.edu/ *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
***************************************************************************/
package edu.brown.utils;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Map;
import org.apache.commons.collections15.map.LRUMap;
import edu.brown.statistics.Histogram;
/**
* @author pavlo
*/
public abstract class MathUtil {
public static final double GEOMETRIC_MEAN_ZERO = 0.001d;
/**
* Fudgey equals for doubles. Round both d0 and d1 to precision decimal
* points and return true if they are within the given fudge factor away
* from each other
*
* @param d0
* @param d1
* @param percision
* @param fudge
* @return
*/
public static final boolean equals(double d0, double d1, int percision, double fudge) {
if (d0 > d1) {
double temp = d1;
d1 = d0;
d0 = temp;
}
double r0 = MathUtil.roundToDecimals(d0, percision);
double r1 = MathUtil.roundToDecimals(d1, percision);
return (r0 >= (r1 - fudge)) && (r0 <= (r1 + fudge));
}
public static final boolean equals(float val0, float val1, float fudge) {
return (Math.abs(val0 - val1) < fudge);
}
public static final boolean equals(double val0, double val1, double fudge) {
return (Math.abs(val0 - val1) < fudge);
}
public static final boolean greaterThanEquals(float val0, float val1, float fudge) {
return (val0 > val1 || MathUtil.equals(val0, val1, fudge));
}
public static final boolean greaterThan(float val0, float val1, float fudge) {
return (Math.abs(val0 - val1) > fudge);
}
public static final boolean lessThanEquals(float val0, float val1, float fudge) {
return (val0 < val1 || MathUtil.equals(val0, val1, fudge));
}
public static final boolean lessThanEquals(double val0, double val1, double fudge) {
return (val0 < val1 || MathUtil.equals(val0, val1, fudge));
}
/**
* Returns the geometric mean of the entries in the input array.
*
* @param values
* @return
*/
public static final double geometricMean(final double[] values) {
return (geometricMean(values, null));
}
/**
* Returns the geometric mean of the entries in the input array. If the
* zero_value is not null, all zeroes will be replaced with that value
*
* @param values
* @param zero_value
* @return
*/
public static final double geometricMean(final double[] values, final Double zero_value) {
double sumLog = 0.0d;
for (double v : values) {
if (v == 0 && zero_value != null)
v = zero_value;
sumLog += Math.log(v);
}
return Math.exp(sumLog / (double) values.length);
}
public static final double arithmeticMean(final double[] values) {
double sum = 0.0d;
for (double v : values) {
sum += v;
}
return sum / (double) values.length;
}
public static final double arithmeticMean(final int[] values) {
int sum = 0;
for (int v : values) {
sum += v;
}
return sum / (double) values.length;
}
public static final <T extends Number> double arithmeticMean(Collection<T> values) {
double sum = 0;
for (T v : values) {
sum += v.doubleValue();
}
return sum / (double) values.size();
}
public static final double weightedMean(final double[] values, final double[] weights) {
double total = 0.0d;
double weight_sum = 0.0d;
assert (values.length == weights.length);
for (int i = 0; i < values.length; i++) {
total += (values[i] * weights[i]);
weight_sum += weights[i];
} // FOR
return (total / (double) weight_sum);
}
public static final <T extends Number> double weightedMean(Histogram<T> h) {
double values[] = new double[h.getValueCount()];
double weights[] = new double[values.length];
int i = 0;
for (T val : h.values()) {
values[i] = val.doubleValue();
weights[i] = h.get(val, 0l);
i++;
if (i >= values.length) break; // HACK
} // FOR
return (MathUtil.weightedMean(values, weights));
}
/**
* Round a double to the given number decimal places
*
* @param d
* @param percision
* @return
*/
public static double roundToDecimals(double d, int percision) {
double p = (double) Math.pow(10, percision);
return (double) Math.round(d * p) / p;
}
/**
* Round a float to the given number decimal places
*
* @param d
* @param percision
* @return
*/
public static final float roundToDecimals(float d, int percision) {
float p = (float) Math.pow(10, percision);
return (float) Math.round(d * p) / p;
}
/**
* Calculate n! Derived from http://chaosinmotion.com/blog/?p=622
*
* @param n
* @return
*/
public static final BigInteger factorial(int n) {
BigInteger ret;
if (n == 0)
return BigInteger.ONE;
if (null != (ret = CACHE_FACTORIAL.get(n)))
return ret;
ret = BigInteger.valueOf(n).multiply(factorial(n - 1));
CACHE_FACTORIAL.put(n, ret);
return ret;
}
private static final Map<Integer, BigInteger> CACHE_FACTORIAL = new LRUMap<Integer, BigInteger>();
/**
* Compute standard deviation Derived from
* http://nscraps.com/Java/720-java-calculate-standard-deviation.htm
* @param data
* @return
*/
public static final double stdev(double...data) {
if (data.length < 2) {
return Double.NaN;
}
double mean = MathUtil.arithmeticMean(data);
double sum = 0;
for (double d : data) {
sum += Math.pow((d - mean), 2);
} // FOR
return Math.sqrt(sum / (data.length - 1));
}
/**
* Compute standard deviation Derived from
* http://nscraps.com/Java/720-java-calculate-standard-deviation.htm
* @param data
* @return
*/
public static final double stdev(int...data) {
if (data.length < 2) {
return Double.NaN;
}
double mean = MathUtil.arithmeticMean(data);
double sum = 0;
for (int d : data) {
sum += Math.pow((d - mean), 2);
} // FOR
return Math.sqrt(sum / (data.length - 1));
}
/**
* Compute standard deviation Derived from
* http://nscraps.com/Java/720-java-calculate-standard-deviation.htm
* @param data
* @return
*/
public static final <T extends Number> double stdev(Collection<T> data) {
if (data.size() < 2) {
return Double.NaN;
}
double mean = MathUtil.arithmeticMean(data);
double sum = 0;
for (T d : data) {
sum += Math.pow((d.doubleValue() - mean), 2);
} // FOR
return Math.sqrt(sum / (data.size() - 1));
}
/** Compute the sum of the given array */
public static final long sum(long...values) {
long total = 0;
for (long v : values) total += v;
return (total);
}
/** Compute the sum of the given array */
public static final int sum(int...values) {
int total = 0;
for (int v : values) total += v;
return (total);
}
}