--- /dev/null
+/*
+ * Created on May 21, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ *
+ * This class is a functon library for common fiscal functions.
+ * <b>Glossary of terms/abbreviations:</b>
+ * <br/>
+ * <ul>
+ * <li><em>FV:</em> Future Value</li>
+ * <li><em>PV:</em> Present Value</li>
+ * <li><em>NPV:</em> Net Present Value</li>
+ * <li><em>PMT:</em> (Periodic) Payment</li>
+ *
+ * </ul>
+ * For more info on the terms/abbreviations please use the references below
+ * (hyperlinks are subject to change):
+ * </br>Online References:
+ * <ol>
+ * <li>GNU Emacs Calc 2.02 Manual: http://theory.uwinnipeg.ca/gnu/calc/calc_203.html</li>
+ * <li>Yahoo Financial Glossary: http://biz.yahoo.com/f/g/nn.html#y</li>
+ * </ol>
+ */
+public class FinanceLib {
+
+ // constants for default values
+
+
+
+ private FinanceLib() {}
+
+ /**
+ * Future value of an amount given the number of payments, rate, amount
+ * of individual payment, present value and boolean value indicating whether
+ * payments are due at the beginning of period
+ * (false => payments are due at end of period)
+ * @param r rate
+ * @param n num of periods
+ * @param y pmt per period
+ * @param f future value
+ * @param t type (true=pmt at end of period, false=pmt at begining of period)
+ * @return
+ */
+ public static double fv(double r, int n, double y, double p, boolean t) {
+ double r1 = r + 1;
+ return ((1-Math.pow(r1, n)) * (t ? r1 : 1) * y ) / r
+ -
+ p*Math.pow(r1, n);
+ }
+
+ /**
+ * Present value of an amount given the number of future payments, rate, amount
+ * of individual payment, future value and boolean value indicating whether
+ * payments are due at the beginning of period
+ * (false => payments are due at end of period)
+ * @param r
+ * @param n
+ * @param y
+ * @param f
+ * @param t
+ * @return
+ */
+ public static double pv(double r, int n, double y, double f, boolean t) {
+ double r1 = r + 1;
+ return (( ( 1 - Math.pow(r1, n) ) / r ) * (t ? r1 : 1) * y - f)
+ /
+ Math.pow(r1, n);
+ }
+
+ /**
+ * calculates the Net Present Value of a principal amount
+ * given the discount rate and a sequence of cash flows
+ * (supplied as an array). If the amounts are income the value should
+ * be positive, else if they are payments and not income, the
+ * value should be negative.
+ * @param r
+ * @param cfs cashflow amounts
+ * @return
+ */
+ public static double npv(double r, double[] cfs) {
+ double npv = 0;
+ double r1 = r + 1;
+ double trate = r1;
+ for (int i=0, iSize=cfs.length; i<iSize; i++) {
+ npv += cfs[i] / trate;
+ trate *= r1;
+ }
+ return npv;
+ }
+
+ /**
+ *
+ * @param r
+ * @param n
+ * @param p
+ * @param f
+ * @param t
+ * @return
+ */
+ public static double pmt(double r, int n, double p, double f, boolean t) {
+ double r1 = r + 1;
+ return ( f + p * Math.pow(r1, n) ) * r
+ /
+ ((t ? r1 : 1) * (1 - Math.pow(r1, n)));
+ }
+
+ /**
+ *
+ * @param r
+ * @param n
+ * @param p
+ * @param f
+ * @param t
+ * @return
+ */
+ public static int nper(double r, double y, double p, double f, boolean t) {
+ double r1 = r + 1;
+ double ryr = (t ? r1 : 1) * y / r;
+ double a1 = ((ryr-f) < 0) ? Math.log(f-ryr) : Math.log(ryr-f);
+ double a2 = ((ryr-f) < 0) ? Math.log(-p-ryr) : Math.log(p+ryr);
+ double a3 = Math.log(r1);
+ double dval = ( a1 - a2 ) / a3;
+
+ return (int) Math.round(dval);
+ }
+
+
+}
--- /dev/null
+/*
+ * Created on May 19, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ * This class is an extension to the standard math library
+ * provided by java.lang.Math class. It follows the Math class
+ * in that it has a private constructor and all static methods.
+ */
+public final class MathX {
+
+
+ private MathX() {}
+
+
+ /**
+ * Returns a value rounded to p digits after decimal.
+ * If p is negative, then the number is rounded to
+ * places to the left of the decimal point. eg.
+ * 10.23 rounded to -1 will give: 10. If p is zero,
+ * the returned value is rounded to the nearest integral
+ * value.
+ * <p>If n is negative, the resulting value is obtained
+ * as the round value of absolute value of n multiplied
+ * by the sign value of n (@see MathX.sign(double d)).
+ * Thus, -0.6666666 rounded to p=0 will give -1 not 0.
+ * <p>If n is NaN, returned value is NaN.
+ * @param n
+ * @param p
+ * @return
+ */
+ public static double round(double n, int p) {
+ double retval;
+
+ if (Double.isNaN(n) || Double.isInfinite(n)) {
+ retval = Double.NaN;
+ }
+ else {
+ if (p != 0) {
+ double temp = Math.pow(10, p);
+ retval = Math.round(n*temp)/temp;
+ }
+ else {
+ retval = Math.round(n);
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * Returns a value rounded-up to p digits after decimal.
+ * If p is negative, then the number is rounded to
+ * places to the left of the decimal point. eg.
+ * 10.23 rounded to -1 will give: 20. If p is zero,
+ * the returned value is rounded to the nearest integral
+ * value.
+ * <p>If n is negative, the resulting value is obtained
+ * as the round-up value of absolute value of n multiplied
+ * by the sign value of n (@see MathX.sign(double d)).
+ * Thus, -0.2 rounded-up to p=0 will give -1 not 0.
+ * <p>If n is NaN, returned value is NaN.
+ * @param n
+ * @param p
+ * @return
+ */
+ public static double roundUp(double n, int p) {
+ double retval;
+
+ if (Double.isNaN(n) || Double.isInfinite(n)) {
+ retval = Double.NaN;
+ }
+ else {
+ if (p != 0) {
+ double temp = Math.pow(10, p);
+ double nat = Math.abs(n*temp);
+
+ retval = sign(n) *
+ ((nat == (long) nat)
+ ? nat / temp
+ : Math.round(nat + 0.5) / temp);
+ }
+ else {
+ double na = Math.abs(n);
+ retval = sign(n) *
+ ((na == (long) na)
+ ? na
+ : (long) na + 1);
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * Returns a value rounded to p digits after decimal.
+ * If p is negative, then the number is rounded to
+ * places to the left of the decimal point. eg.
+ * 10.23 rounded to -1 will give: 10. If p is zero,
+ * the returned value is rounded to the nearest integral
+ * value.
+ * <p>If n is negative, the resulting value is obtained
+ * as the round-up value of absolute value of n multiplied
+ * by the sign value of n (@see MathX.sign(double d)).
+ * Thus, -0.8 rounded-down to p=0 will give 0 not -1.
+ * <p>If n is NaN, returned value is NaN.
+ * @param n
+ * @param p
+ * @return
+ */
+ public static double roundDown(double n, int p) {
+ double retval;
+
+ if (Double.isNaN(n) || Double.isInfinite(n)) {
+ retval = Double.NaN;
+ }
+ else {
+ if (p != 0) {
+ double temp = Math.pow(10, p);
+ retval = sign(n) * Math.round((Math.abs(n)*temp) - 0.5)/temp;
+ }
+ else {
+ retval = (long) n;
+ }
+ }
+
+ return retval;
+ }
+
+
+ /**
+ * If d < 0, returns short -1
+ * <br/>
+ * If d > 0, returns short 1
+ * <br/>
+ * If d == 0, returns short 0
+ * <p> If d is NaN, then 1 will be returned. It is the responsibility
+ * of caller to check for d isNaN if some other value is desired.
+ * @param d
+ * @return
+ */
+ public static short sign(double d) {
+ return (short) ((d == 0)
+ ? 0
+ : (d < 0)
+ ? -1
+ : 1);
+ }
+
+ /**
+ * average of all values
+ * @param values
+ * @return
+ */
+ public static double average(double[] values) {
+ double ave = 0;
+ double sum = 0;
+ for (int i=0, iSize=values.length; i<iSize; i++) {
+ sum += values[i];
+ }
+ ave = sum / values.length;
+ return ave;
+ }
+
+
+ /**
+ * sum of all values
+ * @param values
+ * @return
+ */
+ public static double sum(double[] values) {
+ double sum = 0;
+ for (int i=0, iSize=values.length; i<iSize; i++) {
+ sum += values[i];
+ }
+ return sum;
+ }
+
+ /**
+ * sum of squares of all values
+ * @param values
+ * @return
+ */
+ public static double sumsq(double[] values) {
+ double sumsq = 0;
+ for (int i=0, iSize=values.length; i<iSize; i++) {
+ sumsq += values[i]*values[i];
+ }
+ return sumsq;
+ }
+
+
+ /**
+ * product of all values
+ * @param values
+ * @return
+ */
+ public static double product(double[] values) {
+ double product = 0;
+ if (values!=null && values.length > 0) {
+ product = 1;
+ for (int i=0, iSize=values.length; i<iSize; i++) {
+ product *= values[i];
+ }
+ }
+ return product;
+ }
+
+ /**
+ * min of all values. If supplied array is zero length,
+ * Double.POSITIVE_INFINITY is returned.
+ * @param values
+ * @return
+ */
+ public static double min(double[] values) {
+ double min = Double.POSITIVE_INFINITY;
+ for (int i=0, iSize=values.length; i<iSize; i++) {
+ min = Math.min(min, values[i]);
+ }
+ return min;
+ }
+
+ /**
+ * min of all values. If supplied array is zero length,
+ * Double.NEGATIVE_INFINITY is returned.
+ * @param values
+ * @return
+ */
+ public static double max(double[] values) {
+ double max = Double.NEGATIVE_INFINITY;
+ for (int i=0, iSize=values.length; i<iSize; i++) {
+ max = Math.max(max, values[i]);
+ }
+ return max;
+ }
+
+ /**
+ * Note: this function is different from java.lang.Math.floor(..).
+ * <p>
+ * When n and s are "valid" arguments, the returned value is: Math.floor(n/s) * s;
+ * <br/>
+ * n and s are invalid if any of following conditions are true:
+ * <ul>
+ * <li>s is zero</li>
+ * <li>n is negative and s is positive</li>
+ * <li>n is positive and s is negative</li>
+ * </ul>
+ * In all such cases, Double.NaN is returned.
+ * @param n
+ * @param s
+ * @return
+ */
+ public static double floor(double n, double s) {
+ double f;
+
+ if ((n<0 && s>0) || (n>0 && s<0) || (s==0 && n!=0)) {
+ f = Double.NaN;
+ }
+ else {
+ f = (n==0 || s==0) ? 0 : Math.floor(n/s) * s;
+ }
+
+ return f;
+ }
+
+ /**
+ * Note: this function is different from java.lang.Math.ceil(..).
+ * <p>
+ * When n and s are "valid" arguments, the returned value is: Math.ceiling(n/s) * s;
+ * <br/>
+ * n and s are invalid if any of following conditions are true:
+ * <ul>
+ * <li>s is zero</li>
+ * <li>n is negative and s is positive</li>
+ * <li>n is positive and s is negative</li>
+ * </ul>
+ * In all such cases, Double.NaN is returned.
+ * @param n
+ * @param s
+ * @return
+ */
+ public static double ceiling(double n, double s) {
+ double c;
+
+ if ((n<0 && s>0) || (n>0 && s<0)) {
+ c = Double.NaN;
+ }
+ else {
+ c = (n == 0 || s == 0) ? 0 : Math.ceil(n/s) * s;
+ }
+
+ return c;
+ }
+
+ /**
+ * <br/> for all n >= 1; factorial n = n * (n-1) * (n-2) * ... * 1
+ * <br/> else if n == 0; factorial n = 1
+ * <br/> else if n < 0; factorial n = Double.NaN
+ * <br/> Loss of precision can occur if n is large enough.
+ * If n is large so that the resulting value would be greater
+ * than Double.MAX_VALUE; Double.POSITIVE_INFINITY is returned.
+ * If n < 0, Double.NaN is returned.
+ * @param n
+ * @return
+ */
+ public static double factorial(int n) {
+ double d = 1;
+
+ if (n >= 0) {
+ if (n <= 170) {
+ for (int i=1; i<=n; i++) {
+ d *= i;
+ }
+ }
+ else {
+ d = Double.POSITIVE_INFINITY;
+ }
+ }
+ else {
+ d = Double.NaN;
+ }
+ return d;
+ }
+
+
+ /**
+ * returns the remainder resulting from operation:
+ * n / d.
+ * <br/> The result has the sign of the divisor.
+ * <br/> Examples:
+ * <ul>
+ * <li>mod(3.4, 2) = 1.4</li>
+ * <li>mod(-3.4, 2) = 0.6</li>
+ * <li>mod(-3.4, -2) = -1.4</li>
+ * <li>mod(3.4, -2) = -0.6</li>
+ * </ul>
+ * If d == 0, result is NaN
+ * @param n
+ * @param d
+ * @return
+ */
+ public static double mod(double n, double d) {
+ double result = 0;
+
+ if (d == 0) {
+ result = Double.NaN;
+ }
+ else if (sign(n) == sign(d)) {
+ double t = Math.abs(n / d);
+ t = t - (long) t;
+ result = sign(d) * Math.abs(t * d);
+ }
+ else {
+ double t = Math.abs(n / d);
+ t = t - (long) t;
+ t = Math.ceil(t) - t;
+ result = sign(d) * Math.abs(t * d);
+ }
+
+ return result;
+ }
+
+
+ /**
+ * inverse hyperbolic cosine
+ * @param d
+ * @return
+ */
+ public static double acosh(double d) {
+ return Math.log(Math.sqrt(Math.pow(d, 2) - 1) + d);
+ }
+
+ /**
+ * inverse hyperbolic sine
+ * @param d
+ * @return
+ */
+ public static double asinh(double d) {
+ double d2 = d*d;
+ return Math.log(Math.sqrt(d*d + 1) + d);
+ }
+
+ /**
+ * inverse hyperbolic tangent
+ * @param d
+ * @return
+ */
+ public static double atanh(double d) {
+ return Math.log((1 + d)/(1 - d)) / 2;
+ }
+
+ /**
+ * hyperbolic cosine
+ * @param d
+ * @return
+ */
+ public static double cosh(double d) {
+ double ePowX = Math.pow(Math.E, d);
+ double ePowNegX = Math.pow(Math.E, -d);
+ d = (ePowX + ePowNegX) / 2;
+ return d;
+ }
+
+ /**
+ * hyperbolic sine
+ * @param d
+ * @return
+ */
+ public static double sinh(double d) {
+ double ePowX = Math.pow(Math.E, d);
+ double ePowNegX = Math.pow(Math.E, -d);
+ d = (ePowX - ePowNegX) / 2;
+ return d;
+ }
+
+ /**
+ * hyperbolic tangent
+ * @param d
+ * @return
+ */
+ public static double tanh(double d) {
+ double ePowX = Math.pow(Math.E, d);
+ double ePowNegX = Math.pow(Math.E, -d);
+ d = (ePowX - ePowNegX) / (ePowX + ePowNegX);
+ return d;
+ }
+
+ /**
+ * returns the sum of product of corresponding double value in each
+ * subarray. It is the responsibility of the caller to ensure that
+ * all the subarrays are of equal length. If the subarrays are
+ * not of equal length, the return value can be unpredictable.
+ * @param arrays
+ * @return
+ */
+ public static double sumproduct(double[][] arrays) {
+ double d = 0;
+
+ try {
+ int narr = arrays.length;
+ int arrlen = arrays[0].length;
+
+ for (int j=0; j<arrlen; j++) {
+ double t = 1;
+ for (int i=0; i<narr; i++) {
+ t *= arrays[i][j];
+ }
+ d += t;
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException ae) {
+ d = Double.NaN;
+ }
+
+ return d;
+ }
+
+ /**
+ * returns the sum of difference of squares of corresponding double
+ * value in each subarray: ie. sigma (xarr[i]^2-yarr[i]^2)
+ * <br/>
+ * It is the responsibility of the caller
+ * to ensure that the two subarrays are of equal length. If the
+ * subarrays are not of equal length, the return value can be
+ * unpredictable.
+ * @param arrays
+ * @return
+ */
+ public static double sumx2my2(double[] xarr, double[] yarr) {
+ double d = 0;
+
+ try {
+ for (int i=0, iSize=xarr.length; i<iSize; i++) {
+ d += (xarr[i] + yarr[i]) * (xarr[i] - yarr[i]);
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException ae) {
+ d = Double.NaN;
+ }
+
+ return d;
+ }
+
+ /**
+ * returns the sum of sum of squares of corresponding double
+ * value in each subarray: ie. sigma (xarr[i]^2 + yarr[i]^2)
+ * <br/>
+ * It is the responsibility of the caller
+ * to ensure that the two subarrays are of equal length. If the
+ * subarrays are not of equal length, the return value can be
+ * unpredictable.
+ * @param arrays
+ * @return
+ */
+ public static double sumx2py2(double[] xarr, double[] yarr) {
+ double d = 0;
+
+ try {
+ for (int i=0, iSize=xarr.length; i<iSize; i++) {
+ d += (xarr[i] * xarr[i]) + (yarr[i] * yarr[i]);
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException ae) {
+ d = Double.NaN;
+ }
+
+ return d;
+ }
+
+
+ /**
+ * returns the sum of squares of difference of corresponding double
+ * value in each subarray: ie. sigma ( (xarr[i]-yarr[i])^2 )
+ * <br/>
+ * It is the responsibility of the caller
+ * to ensure that the two subarrays are of equal length. If the
+ * subarrays are not of equal length, the return value can be
+ * unpredictable.
+ * @param arrays
+ * @return
+ */
+ public static double sumxmy2(double[] xarr, double[] yarr) {
+ double d = 0;
+
+ try {
+ for (int i=0, iSize=xarr.length; i<iSize; i++) {
+ double t = (xarr[i] - yarr[i]);
+ d += t * t;
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException ae) {
+ d = Double.NaN;
+ }
+
+ return d;
+ }
+
+ /**
+ * returns the total number of combinations possible when
+ * k items are chosen out of total of n items. If the number
+ * is too large, loss of precision may occur (since returned
+ * value is double). If the returned value is larger than
+ * Double.MAX_VALUE, Double.POSITIVE_INFINITY is returned.
+ * If either of the parameters is negative, Double.NaN is returned.
+ * @param n
+ * @param k
+ * @return
+ */
+ public static double nChooseK(int n, int k) {
+ double d = 1;
+ if (n<0 || k<0 || n<k) {
+ d= Double.NaN;
+ }
+ else {
+ int minnk = Math.min(n-k, k);
+ int maxnk = Math.max(n-k, k);
+ for (int i=maxnk; i<n; i++) {
+ d *= i+1;
+ }
+ d /= factorial(minnk);
+ }
+
+ return d;
+ }
+
+}
--- /dev/null
+/*
+ * Created on May 22, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ * This is the super class for all excel function evaluator
+ * classes that take variable number of operands, and
+ * where the order of operands does not matter
+ */
+public abstract class MultiOperandNumericFunction extends NumericFunction {
+
+ private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
+ new ValueEvalToNumericXlator((short) (
+ ValueEvalToNumericXlator.BOOL_IS_PARSED
+ | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
+ | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
+ //| ValueEvalToNumericXlator.STRING_IS_PARSED
+ | ValueEvalToNumericXlator.REF_STRING_IS_PARSED
+ | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
+ //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
+ //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
+ //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
+ //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
+ ));
+
+ private static final int DEFAULT_MAX_NUM_OPERANDS = 30;
+
+ /**
+ * this is the default impl for the factory method getXlator
+ * of the super class NumericFunction. Subclasses can override this method
+ * if they desire to return a different ValueEvalToNumericXlator instance
+ * than the default.
+ */
+ protected ValueEvalToNumericXlator getXlator() {
+ return DEFAULT_NUM_XLATOR;
+ }
+
+ /**
+ * Maximum number of operands accepted by this function.
+ * Subclasses may override to change default value.
+ * @return
+ */
+ protected int getMaxNumOperands() {
+ return DEFAULT_MAX_NUM_OPERANDS;
+ }
+
+ /**
+ * Returns a double array that contains values for the numeric cells
+ * from among the list of operands. Blanks and Blank equivalent cells
+ * are ignored. Error operands or cells containing operands of type
+ * that are considered invalid and would result in #VALUE! error in
+ * excel cause this function to return null.
+ *
+ * @param operands
+ * @param srcRow
+ * @param srcCol
+ * @return
+ */
+ protected double[] getNumberArray(Eval[] operands, int srcRow, short srcCol) {
+ double[] retval = new double[30];
+ int count = 0;
+
+ outer: do { // goto simulator loop
+ if (operands.length > getMaxNumOperands()) {
+ break outer;
+ }
+ else {
+ for (int i=0, iSize=operands.length; i<iSize; i++) {
+ double[] temp = getNumberArray(operands[i], srcRow, srcCol);
+ if (temp == null) {
+ retval = null; // error occurred.
+ break;
+ }
+ retval = putInArray(retval, count, temp);
+ count += temp.length;
+ }
+ }
+ } while (false); // end goto simulator loop
+
+ if (retval != null) {
+ double[] temp = retval;
+ retval = new double[count];
+ System.arraycopy(temp, 0, retval, 0, count);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Same as getNumberArray(Eval[], int, short) except that this
+ * takes Eval instead of Eval[].
+ * @param operand
+ * @param srcRow
+ * @param srcCol
+ * @return
+ */
+ protected double[] getNumberArray(Eval operand, int srcRow, short srcCol) {
+ double[] retval;
+ int count = 0;
+
+ if (operand instanceof AreaEval) {
+ AreaEval ae = (AreaEval) operand;
+ ValueEval[] values = ae.getValues();
+ retval = new double[values.length];
+ for (int j=0, jSize=values.length; j<jSize; j++) {
+ /*
+ * TODO: For an AreaEval, we are constructing a RefEval
+ * per element.
+ * For now this is a tempfix solution since this may
+ * require a more generic fix at the level of
+ * HSSFFormulaEvaluator where we store an array
+ * of RefEvals as the "values" array.
+ */
+ RefEval re = (values[j] instanceof RefEval)
+ ? new Ref2DEval(null, ((RefEval) values[j]).getInnerValueEval(), true)
+ : new Ref2DEval(null, values[j], false);
+ ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
+
+ if (ve instanceof NumericValueEval) {
+ NumericValueEval nve = (NumericValueEval) ve;
+ retval = putInArray(retval, count++, nve.getNumberValue());
+ }
+ else if (ve instanceof BlankEval) {} // ignore operand
+ else {
+ retval = null; // null => indicate to calling subclass that error occurred
+ break;
+ }
+ }
+ }
+ else { // for ValueEvals other than AreaEval
+ retval = new double[1];
+ ValueEval ve = singleOperandEvaluate(operand, srcRow, srcCol);
+
+ if (ve instanceof NumericValueEval) {
+ NumericValueEval nve = (NumericValueEval) ve;
+ retval = putInArray(retval, count++, nve.getNumberValue());
+ }
+ else if (ve instanceof BlankEval) {} // ignore operand
+ else {
+ retval = null; // null => indicate to calling subclass that error occurred
+ }
+ }
+
+ if (retval != null && retval.length >= 1) {
+ double[] temp = retval;
+ retval = new double[count];
+ System.arraycopy(temp, 0, retval, 0, count);
+ }
+
+ return retval;
+ }
+
+ /**
+ * puts d at position pos in array arr. If pos is greater than arr, the
+ * array is dynamically resized (using a simple doubling rule).
+ * @param arr
+ * @param pos
+ * @param d
+ * @return
+ */
+ private static double[] putInArray(double[] arr, int pos, double d) {
+ double[] tarr = arr;
+ while (pos >= arr.length) {
+ arr = new double[arr.length << 1];
+ }
+ if (tarr.length != arr.length) {
+ System.arraycopy(tarr, 0, arr, 0, tarr.length);
+ }
+ arr[pos] = d;
+ return arr;
+ }
+
+ private static double[] putInArray(double[] arr, int pos, double[] d) {
+ double[] tarr = arr;
+ while (pos+d.length >= arr.length) {
+ arr = new double[arr.length << 1];
+ }
+ if (tarr.length != arr.length) {
+ System.arraycopy(tarr, 0, arr, 0, tarr.length);
+ }
+ for (int i=0, iSize=d.length; i<iSize; i++) {
+ arr[pos+i] = d[i];
+ }
+ return arr;
+ }
+
+ protected static boolean areSubArraysConsistent(double[][] values) {
+ boolean retval = false;
+
+ outer: do {
+ if (values != null && values.length > 0) {
+ if (values[0] == null)
+ break outer;
+ int len = values[0].length;
+ for (int i=1, iSize=values.length; i<iSize; i++) {
+ if (values[i] == null)
+ break outer;
+ int tlen = values[i].length;
+ if (len != tlen) {
+ break outer;
+ }
+ }
+ }
+ retval = true;
+ } while (false);
+ return retval;
+ }
+
+}
--- /dev/null
+/*
+ * Created on May 30, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+import java.util.Arrays;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ * Library for common statistics functions
+ */
+public class StatsLib {
+
+ private StatsLib() {}
+
+
+ /**
+ * returns the mean of deviations from mean.
+ * @param v
+ * @return
+ */
+ public static double avedev(double[] v) {
+ double r = 0;
+ double m = 0;
+ double s = 0;
+ for (int i=0, iSize=v.length; i<iSize; i++) {
+ s += v[i];
+ }
+ m = s / v.length;
+ s = 0;
+ for (int i=0, iSize=v.length; i<iSize; i++) {
+ s += Math.abs(v[i]-m);
+ }
+ r = s / v.length;
+ return r;
+ }
+
+ public static double stdev(double[] v) {
+ double r = Double.NaN;
+ if (v!=null && v.length > 1) {
+ r = Math.sqrt( devsq(v) / (v.length - 1) );
+ }
+ return r;
+ }
+
+ /**
+ * if v is zero length or contains no duplicates, return value
+ * is Double.NaN. Else returns the value that occurs most times
+ * and if there is a tie, returns the first such value.
+ * @param v
+ * @return
+ */
+ public static double mode(double[] v) {
+ double r = Double.NaN;
+
+ // very naive impl, may need to be optimized
+ if (v!=null && v.length > 1) {
+ int[] counts = new int[v.length];
+ Arrays.fill(counts, 1);
+ for (int i=0, iSize=v.length; i<iSize; i++) {
+ for (int j=i+1, jSize=v.length; j<jSize; j++) {
+ if (v[i] == v[j]) counts[i]++;
+ }
+ }
+ double maxv = 0;
+ int maxc = 0;
+ for (int i=0, iSize=counts.length; i<iSize; i++) {
+ if (counts[i] > maxc) {
+ maxv = v[i];
+ maxc = counts[i];
+ }
+ }
+ r = (maxc > 1) ? maxv : Double.NaN; // "no-dups" check
+ }
+ return r;
+ }
+
+ public static double median(double[] v) {
+ double r = Double.NaN;
+
+ if (v!=null && v.length >= 1) {
+ int n = v.length;
+ Arrays.sort(v);
+ r = (n % 2 == 0)
+ ? (v[n / 2] + v[n / 2 - 1]) / 2
+ : v[n / 2];
+ }
+
+ return r;
+ }
+
+
+ public static double devsq(double[] v) {
+ double r = Double.NaN;
+ if (v!=null && v.length >= 1) {
+ double m = 0;
+ double s = 0;
+ int n = v.length;
+ for (int i=0; i<n; i++) {
+ s += v[i];
+ }
+ m = s / n;
+ s = 0;
+ for (int i=0; i<n; i++) {
+ s += (v[i]- m) * (v[i] - m);
+ }
+
+ r = (n == 1)
+ ? 0
+ : s;
+ }
+ return r;
+ }
+
+ /**
+ * returns the kth largest element in the array. Duplicates
+ * are considered as distinct values. Hence, eg.
+ * for array {1,2,4,3,3} & k=2, returned value is 3.
+ * <br/>
+ * k <= 0 & k >= v.length and null or empty arrays
+ * will result in return value Double.NaN
+ * @param v
+ * @param k
+ * @return
+ */
+ public static double kthLargest(double[] v, int k) {
+ double r = Double.NaN;
+ k--; // since arrays are 0-based
+ if (v!=null && v.length > k && k >= 0) {
+ Arrays.sort(v);
+ r = v[v.length-k-1];
+ }
+ return r;
+ }
+
+ /**
+ * returns the kth smallest element in the array. Duplicates
+ * are considered as distinct values. Hence, eg.
+ * for array {1,1,2,4,3,3} & k=2, returned value is 1.
+ * <br/>
+ * k <= 0 & k >= v.length or null array or empty array
+ * will result in return value Double.NaN
+ * @param v
+ * @param k
+ * @return
+ */
+ public static double kthSmallest(double[] v, int k) {
+ double r = Double.NaN;
+ k--; // since arrays are 0-based
+ if (v!=null && v.length > k && k >= 0) {
+ Arrays.sort(v);
+ r = v[k];
+ }
+ return r;
+ }
+}
--- /dev/null
+/*
+ * Created on May 22, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public abstract class TextFunction implements Function {
+
+ protected static final String EMPTY_STRING = "";
+
+ protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
+ ValueEval retval;
+ if (eval instanceof AreaEval) {
+ AreaEval ae = (AreaEval) eval;
+ if (ae.contains(srcRow, srcCol)) { // circular ref!
+ retval = ErrorEval.CIRCULAR_REF_ERROR;
+ }
+ else if (ae.isRow()) {
+ if (ae.containsColumn(srcCol)) {
+ ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
+ retval = attemptXlateToText(ve);
+ }
+ else {
+ retval = ErrorEval.VALUE_INVALID;
+ }
+ }
+ else if (ae.isColumn()) {
+ if (ae.containsRow(srcRow)) {
+ ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
+ retval = attemptXlateToText(ve);
+ }
+ else {
+ retval = ErrorEval.VALUE_INVALID;
+ }
+ }
+ else {
+ retval = ErrorEval.VALUE_INVALID;
+ }
+ }
+ else {
+ retval = attemptXlateToText((ValueEval) eval);
+ }
+ return retval;
+ }
+
+
+ /**
+ * converts from Different ValueEval types to StringEval.
+ * Note: AreaEvals are not handled, if arg is an AreaEval,
+ * the returned value is ErrorEval.VALUE_INVALID
+ * @param ve
+ * @return
+ */
+ protected ValueEval attemptXlateToText(ValueEval ve) {
+ ValueEval retval;
+ if (ve instanceof StringValueEval) {
+ retval = ve;
+ }
+ else if (ve instanceof RefEval) {
+ RefEval re = (RefEval) ve;
+ ValueEval ive = re.getInnerValueEval();
+ if (ive instanceof StringValueEval) {
+ retval = ive;
+ }
+ else if (ive instanceof BlankEval) {
+ retval = ive;
+ }
+ else {
+ retval = ErrorEval.VALUE_INVALID;
+ }
+ }
+ else if (ve instanceof BlankEval) {
+ retval = ve;
+ }
+ else {
+ retval = ErrorEval.VALUE_INVALID;
+ }
+ return retval;
+ }
+}
--- /dev/null
+/*
+ * Created on May 29, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public abstract class XYNumericFunction extends NumericFunction {
+ protected static final int X = 0;
+ protected static final int Y = 1;
+
+ private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
+ new ValueEvalToNumericXlator((short) (
+ ValueEvalToNumericXlator.BOOL_IS_PARSED
+ | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
+ | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
+ //| ValueEvalToNumericXlator.STRING_IS_PARSED
+ | ValueEvalToNumericXlator.REF_STRING_IS_PARSED
+ | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
+ //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
+ //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
+ //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
+ //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
+ ));
+
+ /**
+ * this is the default impl for the factory method getXlator
+ * of the super class NumericFunction. Subclasses can override this method
+ * if they desire to return a different ValueEvalToNumericXlator instance
+ * than the default.
+ */
+ protected ValueEvalToNumericXlator getXlator() {
+ return DEFAULT_NUM_XLATOR;
+ }
+
+ protected int getMaxNumOperands() {
+ return 30;
+ }
+
+ /**
+ * Returns a double array that contains values for the numeric cells
+ * from among the list of operands. Blanks and Blank equivalent cells
+ * are ignored. Error operands or cells containing operands of type
+ * that are considered invalid and would result in #VALUE! error in
+ * excel cause this function to return null.
+ *
+ * @param operands
+ * @param srcRow
+ * @param srcCol
+ * @return
+ */
+ protected double[][] getNumberArray(Eval[] xops, Eval[] yops, int srcRow, short srcCol) {
+ double[][] retval = new double[2][30];
+ int count = 0;
+
+ if (xops.length > getMaxNumOperands()
+ || yops.length > getMaxNumOperands()
+ || xops.length != yops.length) {
+ retval = null;
+ }
+ else {
+
+ for (int i=0, iSize=xops.length; i<iSize; i++) {
+ Eval xEval = xops[i];
+ Eval yEval = yops[i];
+
+ if (isNumberEval(xEval) && isNumberEval(yEval)) {
+ retval[X] = ensureCapacity(retval[X], count);
+ retval[Y] = ensureCapacity(retval[Y], count);
+ retval[X][count] = getDoubleValue(xEval);
+ retval[Y][count] = getDoubleValue(yEval);
+ if (Double.isNaN(retval[X][count]) || Double.isNaN(retval[Y][count])) {
+ retval = null;
+ break;
+ }
+ count++;
+ }
+ }
+ }
+
+ if (retval != null) {
+ double[][] temp = retval;
+ retval[X] = trimToSize(retval[X], count);
+ retval[Y] = trimToSize(retval[Y], count);
+ }
+
+ return retval;
+ }
+
+ protected double[][] getValues(Eval[] operands, int srcCellRow, short srcCellCol) {
+ double[][] retval = null;
+
+ outer: do {
+ if (operands.length == 2) {
+ Eval[] xEvals = new Eval[1];
+ Eval[] yEvals = new Eval[1];
+ if (operands[X] instanceof AreaEval) {
+ AreaEval ae = (AreaEval) operands[0];
+ xEvals = ae.getValues();
+ }
+ else if (operands[X] instanceof ErrorEval) {
+ break outer;
+ }
+ else {
+ xEvals[0] = operands[X];
+ }
+
+ if (operands[Y] instanceof AreaEval) {
+ AreaEval ae = (AreaEval) operands[Y];
+ yEvals = ae.getValues();
+ }
+ else if (operands[Y] instanceof ErrorEval) {
+ break outer;
+ }
+ else {
+ yEvals[0] = operands[Y];
+ }
+
+ retval = getNumberArray(xEvals, yEvals, srcCellRow, srcCellCol);
+ }
+ } while (false);
+
+ return retval;
+ }
+
+
+ protected static double[] ensureCapacity(double[] arr, int pos) {
+ double[] temp = arr;
+ while (pos >= arr.length) {
+ arr = new double[arr.length << 2];
+ }
+ if (temp.length != arr.length)
+ System.arraycopy(temp, 0, arr, 0, temp.length);
+ return arr;
+ }
+
+ protected static double[] trimToSize(double[] arr, int len) {
+ double[] tarr = arr;
+ if (arr.length > len) {
+ tarr = new double[len];
+ System.arraycopy(arr, 0, tarr, 0, len);
+ }
+ return tarr;
+ }
+
+ protected static boolean isNumberEval(Eval eval) {
+ boolean retval = false;
+
+ if (eval instanceof NumberEval) {
+ retval = true;
+ }
+ else if (eval instanceof RefEval) {
+ RefEval re = (RefEval) eval;
+ ValueEval ve = re.getInnerValueEval();
+ retval = (ve instanceof NumberEval);
+ }
+
+ return retval;
+ }
+
+ protected static double getDoubleValue(Eval eval) {
+ double retval = 0;
+ if (eval instanceof NumberEval) {
+ NumberEval ne = (NumberEval) eval;
+ retval = ne.getNumberValue();
+ }
+ else if (eval instanceof RefEval) {
+ RefEval re = (RefEval) eval;
+ ValueEval ve = re.getInnerValueEval();
+ retval = (ve instanceof NumberEval)
+ ? ((NumberEval) ve).getNumberValue()
+ : Double.NaN;
+ }
+ else if (eval instanceof ErrorEval) {
+ retval = Double.NaN;
+ }
+ return retval;
+ }
+}
--- /dev/null
+/*
+ * Created on May 29, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public abstract class AbstractNumericTestCase extends TestCase {
+
+ public static final double POS_ZERO = 1E-4;
+ public static final double DIFF_TOLERANCE_FACTOR = 1E-8;
+
+ public void setUp() {
+ }
+
+ public void tearDown() {
+ }
+
+ /**
+ * Why doesnt JUnit have a method like this for doubles?
+ * The current impl (3.8.1) of Junit has a retar*** method
+ * for comparing doubles. DO NOT use that.
+ * TODO: This class should really be in an abstract super class
+ * to avoid code duplication across this project.
+ * @param message
+ * @param baseval
+ * @param checkval
+ */
+ public static void assertEquals(String message, double baseval, double checkval, double almostZero, double diffToleranceFactor) {
+ double posZero = Math.abs(almostZero);
+ double negZero = -1 * posZero;
+ if (Double.isNaN(baseval)) {
+ assertTrue(message+": Expected " + baseval + " but was " + checkval
+ , Double.isNaN(baseval));
+ }
+ else if (Double.isInfinite(baseval)) {
+ assertTrue(message+": Expected " + baseval + " but was " + checkval
+ , Double.isInfinite(baseval) && ((baseval<0) == (checkval<0)));
+ }
+ else {
+ assertTrue(message+": Expected " + baseval + " but was " + checkval
+ ,baseval != 0
+ ? Math.abs(baseval - checkval) <= Math.abs(diffToleranceFactor * baseval)
+ : checkval < posZero && checkval > negZero);
+ }
+ }
+
+ public static void assertEquals(String msg, double baseval, double checkval) {
+ assertEquals(msg, baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR);
+ }
+
+}
--- /dev/null
+/*
+ * Created on May 23, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public class TestFinanceLib extends AbstractNumericTestCase {
+
+ public void testFv() {
+ double f, r, y, p, x;
+ int n;
+ boolean t = false;
+
+ r = 1; n = 10; y = 100; p = 10000; t = false;
+ f = FinanceLib.fv(r, n, y, p, t);
+ x = -10342300;
+ assertEquals("fv ", x, f);
+
+ r = 1; n = 10; y = 100; p = 10000; t = true;
+ f = FinanceLib.fv(r, n, y, p, t);
+ x = -10444600;
+ assertEquals("fv ", x, f);
+
+ r = 2; n = 12; y = 120; p = 12000; t = false;
+ f = FinanceLib.fv(r, n, y, p, t);
+ x = -6409178400d;
+ assertEquals("fv ", x, f);
+
+ r = 2; n = 12; y = 120; p = 12000; t = true;
+ f = FinanceLib.fv(r, n, y, p, t);
+ x = -6472951200d;
+ assertEquals("fv ", x, f);
+
+ // cross tests with pv
+ r = 2.95; n = 13; y = 13000; p = -4406.78544294496; t = false;
+ f = FinanceLib.fv(r, n, y, p, t);
+ x = 333891.230010986; // as returned by excel
+ assertEquals("fv ", x, f);
+
+ r = 2.95; n = 13; y = 13000; p = -17406.7852148156; t = true;
+ f = FinanceLib.fv(r, n, y, p, t);
+ x = 333891.230102539; // as returned by excel
+ assertEquals("fv ", x, f);
+
+ }
+ public void testNpv() {
+ double r, v[], npv, x;
+
+ r = 1; v = new double[]{100, 200, 300, 400};
+ npv = FinanceLib.npv(r, v);
+ x = 162.5;
+ assertEquals("npv ", x, npv);
+
+ r = 2.5; v = new double[]{1000, 666.66666, 333.33, 12.2768416};
+ npv = FinanceLib.npv(r, v);
+ x = 347.99232604144827;
+ assertEquals("npv ", x, npv);
+
+ r = 12.33333; v = new double[]{1000, 0, -900, -7777.5765};
+ npv = FinanceLib.npv(r, v);
+ x = 74.3742433377061;
+ assertEquals("npv ", x, npv);
+
+ r = 0.05; v = new double[]{200000, 300000.55, 400000, 1000000, 6000000, 7000000, -300000};
+ npv = FinanceLib.npv(r, v);
+ x = 11342283.4233124;
+ assertEquals("npv ", x, npv);
+ }
+ public void testPmt() {
+ double f, r, y, p, x;
+ int n;
+ boolean t = false;
+
+ // cross check with pv
+ r = 1; n = 10; p = -109.66796875; f = 10000; t = false;
+ y = FinanceLib.pmt(r, n, p, f, t);
+ x = 100;
+ assertEquals("pmt ", x, y);
+
+ r = 1; n = 10; p = -209.5703125; f = 10000; t = true;
+ y = FinanceLib.pmt(r, n, p, f, t);
+ x = 100;
+ assertEquals("pmt ", x, y);
+
+ // cross check with fv
+ r = 2; n = 12; f = -6409178400d; p = 12000; t = false;
+ y = FinanceLib.pmt(r, n, p, f, t);
+ x = 120;
+ assertEquals("pmt ", x, y);
+
+ r = 2; n = 12; f = -6472951200d; p = 12000; t = true;
+ y = FinanceLib.pmt(r, n, p, f, t);
+ x = 120;
+ assertEquals("pmt ", x, y);
+ }
+
+ public void testPv() {
+ double f, r, y, p, x;
+ int n;
+ boolean t = false;
+
+ r = 1; n = 10; y = 100; f = 10000; t = false;
+ p = FinanceLib.pv(r, n, y, f, t);
+ x = -109.66796875;
+ assertEquals("pv ", x, p);
+
+ r = 1; n = 10; y = 100; f = 10000; t = true;
+ p = FinanceLib.pv(r, n, y, f, t);
+ x = -209.5703125;
+ assertEquals("pv ", x, p);
+
+ r = 2.95; n = 13; y = 13000; f = 333891.23; t = false;
+ p = FinanceLib.pv(r, n, y, f, t);
+ x = -4406.78544294496;
+ assertEquals("pv ", x, p);
+
+ r = 2.95; n = 13; y = 13000; f = 333891.23; t = true;
+ p = FinanceLib.pv(r, n, y, f, t);
+ x = -17406.7852148156;
+ assertEquals("pv ", x, p);
+
+ // cross tests with fv
+ r = 2; n = 12; y = 120; f = -6409178400d; t = false;
+ p = FinanceLib.pv(r, n, y, f, t);
+ x = 12000;
+ assertEquals("pv ", x, p);
+
+ r = 2; n = 12; y = 120; f = -6472951200d; t = true;
+ p = FinanceLib.pv(r, n, y, f, t);
+ x = 12000;
+ assertEquals("pv ", x, p);
+
+ }
+
+ public void testNper() {
+ double f, r, y, p, x;
+ int n;
+ boolean t = false;
+
+ // cross check with pv
+ r = 1; y = 100; p = -109.66796875; f = 10000; t = false;
+ n = FinanceLib.nper(r, y, p, f, t);
+ x = 10;
+ assertEquals("nper ", x, n);
+
+ r = 1; y = 100; p = -209.5703125; f = 10000; t = true;
+ n = FinanceLib.nper(r, y, p, f, t);
+ x = 10;
+ assertEquals("nper ", x, n);
+
+ // cross check with fv
+ r = 2; y = 120; f = -6409178400d; p = 12000; t = false;
+ n = FinanceLib.nper(r, y, p, f, t);
+ x = 12;
+ assertEquals("nper ", x, n);
+
+ r = 2; y = 120; f = -6472951200d; p = 12000; t = true;
+ n = FinanceLib.nper(r, y, p, f, t);
+ x = 12;
+ assertEquals("nper ", x, n);
+ }
+}
--- /dev/null
+/*
+ * Created on May 23, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public class TestMathX extends AbstractNumericTestCase {
+
+ public void testAcosh() {
+ double d = 0;
+
+ d = MathX.acosh(0);
+ assertTrue("Acosh 0 is NaN", Double.isNaN(d));
+
+ d = MathX.acosh(1);
+ assertEquals("Acosh 1 ", 0, d);
+
+ d = MathX.acosh(-1);
+ assertTrue("Acosh -1 is NaN", Double.isNaN(d));
+
+ d = MathX.acosh(100);
+ assertEquals("Acosh 100 ", 5.298292366d, d);
+
+ d = MathX.acosh(101.001);
+ assertEquals("Acosh 101.001 ", 5.308253091d, d);
+
+ d = MathX.acosh(200000);
+ assertEquals("Acosh 200000 ", 12.89921983d, d);
+
+ }
+
+ public void testAsinh() {
+ double d = 0;
+
+ d = MathX.asinh(0);
+ assertEquals("asinh 0", d, 0);
+
+ d = MathX.asinh(1);
+ assertEquals("asinh 1 ", 0.881373587, d);
+
+ d = MathX.asinh(-1);
+ assertEquals("asinh -1 ", -0.881373587, d);
+
+ d = MathX.asinh(-100);
+ assertEquals("asinh -100 ", -5.298342366, d);
+
+ d = MathX.asinh(100);
+ assertEquals("asinh 100 ", 5.298342366, d);
+
+ d = MathX.asinh(200000);
+ assertEquals("asinh 200000", 12.899219826096400, d);
+
+ d = MathX.asinh(-200000);
+ assertEquals("asinh -200000 ", -12.899223853137, d);
+
+ }
+
+ public void testAtanh() {
+ double d = 0;
+ d = MathX.atanh(0);
+ assertEquals("atanh 0", d, 0);
+
+ d = MathX.atanh(1);
+ assertEquals("atanh 1 ", Double.POSITIVE_INFINITY, d);
+
+ d = MathX.atanh(-1);
+ assertEquals("atanh -1 ", Double.NEGATIVE_INFINITY, d);
+
+ d = MathX.atanh(-100);
+ assertEquals("atanh -100 ", Double.NaN, d);
+
+ d = MathX.atanh(100);
+ assertEquals("atanh 100 ", Double.NaN, d);
+
+ d = MathX.atanh(200000);
+ assertEquals("atanh 200000", Double.NaN, d);
+
+ d = MathX.atanh(-200000);
+ assertEquals("atanh -200000 ", Double.NaN, d);
+
+ d = MathX.atanh(0.1);
+ assertEquals("atanh 0.1", 0.100335348, d);
+
+ d = MathX.atanh(-0.1);
+ assertEquals("atanh -0.1 ", -0.100335348, d);
+
+ }
+
+ public void testCosh() {
+ double d = 0;
+ d = MathX.cosh(0);
+ assertEquals("cosh 0", 1, d);
+
+ d = MathX.cosh(1);
+ assertEquals("cosh 1 ", 1.543080635, d);
+
+ d = MathX.cosh(-1);
+ assertEquals("cosh -1 ", 1.543080635, d);
+
+ d = MathX.cosh(-100);
+ assertEquals("cosh -100 ", 1.344058570908070E+43, d);
+
+ d = MathX.cosh(100);
+ assertEquals("cosh 100 ", 1.344058570908070E+43, d);
+
+ d = MathX.cosh(15);
+ assertEquals("cosh 15", 1634508.686, d);
+
+ d = MathX.cosh(-15);
+ assertEquals("cosh -15 ", 1634508.686, d);
+
+ d = MathX.cosh(0.1);
+ assertEquals("cosh 0.1", 1.005004168, d);
+
+ d = MathX.cosh(-0.1);
+ assertEquals("cosh -0.1 ", 1.005004168, d);
+
+ }
+
+ public void testTanh() {
+ double d = 0;
+ d = MathX.tanh(0);
+ assertEquals("tanh 0", 0, d);
+
+ d = MathX.tanh(1);
+ assertEquals("tanh 1 ", 0.761594156, d);
+
+ d = MathX.tanh(-1);
+ assertEquals("tanh -1 ", -0.761594156, d);
+
+ d = MathX.tanh(-100);
+ assertEquals("tanh -100 ", -1, d);
+
+ d = MathX.tanh(100);
+ assertEquals("tanh 100 ", 1, d);
+
+ d = MathX.tanh(15);
+ assertEquals("tanh 15", 1, d);
+
+ d = MathX.tanh(-15);
+ assertEquals("tanh -15 ", -1, d);
+
+ d = MathX.tanh(0.1);
+ assertEquals("tanh 0.1", 0.099667995, d);
+
+ d = MathX.tanh(-0.1);
+ assertEquals("tanh -0.1 ", -0.099667995, d);
+
+ }
+
+ public void testMax() {
+ double[] d = new double[100];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ double m = MathX.max(d);
+ assertEquals("Max ", 20.1, m);
+
+ d = new double[1000];
+ m = MathX.max(d);
+ assertEquals("Max ", 0, m);
+
+ d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1;
+ d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1;
+ d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1;
+ d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1;
+ d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1;
+ m = MathX.max(d);
+ assertEquals("Max ", 20.1, m);
+
+ d = new double[20];
+ d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1;
+ d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1;
+ d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1;
+ d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1;
+ d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1;
+ m = MathX.max(d);
+ assertEquals("Max ", -1.1, m);
+
+ }
+
+ public void testMin() {
+ double[] d = new double[100];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ double m = MathX.min(d);
+ assertEquals("Min ", 0, m);
+
+ d = new double[20];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ m = MathX.min(d);
+ assertEquals("Min ", 1.1, m);
+
+ d = new double[1000];
+ m = MathX.min(d);
+ assertEquals("Min ", 0, m);
+
+ d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1;
+ d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1;
+ d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1;
+ d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1;
+ d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1;
+ m = MathX.min(d);
+ assertEquals("Min ", -19.1, m);
+
+ d = new double[20];
+ d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1;
+ d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1;
+ d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1;
+ d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1;
+ d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1;
+ m = MathX.min(d);
+ assertEquals("Min ", -20.1, m);
+ }
+
+ public void testProduct() {
+ double[] d = new double[100];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ double m = MathX.min(d);
+ assertEquals("Min ", 0, m);
+
+ d = new double[20];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ m = MathX.min(d);
+ assertEquals("Min ", 1.1, m);
+
+ d = new double[1000];
+ m = MathX.min(d);
+ assertEquals("Min ", 0, m);
+
+ d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1;
+ d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1;
+ d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1;
+ d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1;
+ d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1;
+ m = MathX.min(d);
+ assertEquals("Min ", -19.1, m);
+
+ d = new double[20];
+ d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1;
+ d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1;
+ d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1;
+ d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1;
+ d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1;
+ m = MathX.min(d);
+ assertEquals("Min ", -20.1, m);
+ }
+
+ public void testMod() {
+ }
+
+ public void testNChooseK() {
+ int n=100;
+ int k=50;
+ double d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 1.00891344545564E29, d);
+
+ n = -1; k = 1;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", Double.NaN, d);
+
+ n = 1; k = -1;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", Double.NaN, d);
+
+ n = 0; k = 1;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", Double.NaN, d);
+
+ n = 1; k = 0;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 1, d);
+
+ n = 10; k = 9;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 10, d);
+
+ n = 10; k = 10;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 1, d);
+
+ n = 10; k = 1;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 10, d);
+
+ n = 1000; k = 1;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 1000, d); // awesome ;)
+
+ n = 1000; k = 2;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 499500, d); // awesome ;)
+
+ n = 13; k = 7;
+ d = MathX.nChooseK(n, k);
+ assertEquals("NChooseK ", 1716, d);
+
+ }
+
+ public void testSign() {
+ final short minus = -1;
+ final short zero = 0;
+ final short plus = 1;
+ double d = 0;
+
+
+ assertEquals("Sign ", minus, MathX.sign(minus));
+ assertEquals("Sign ", plus, MathX.sign(plus));
+ assertEquals("Sign ", zero, MathX.sign(zero));
+
+ d = 0;
+ assertEquals("Sign ", zero, MathX.sign(d));
+
+ d = -1.000001;
+ assertEquals("Sign ", minus, MathX.sign(d));
+
+ d = -.000001;
+ assertEquals("Sign ", minus, MathX.sign(d));
+
+ d = -1E-200;
+ assertEquals("Sign ", minus, MathX.sign(d));
+
+ d = Double.NEGATIVE_INFINITY;
+ assertEquals("Sign ", minus, MathX.sign(d));
+
+ d = -200.11;
+ assertEquals("Sign ", minus, MathX.sign(d));
+
+ d = -2000000000000.11;
+ assertEquals("Sign ", minus, MathX.sign(d));
+
+ d = 1.000001;
+ assertEquals("Sign ", plus, MathX.sign(d));
+
+ d = .000001;
+ assertEquals("Sign ", plus, MathX.sign(d));
+
+ d = 1E-200;
+ assertEquals("Sign ", plus, MathX.sign(d));
+
+ d = Double.POSITIVE_INFINITY;
+ assertEquals("Sign ", plus, MathX.sign(d));
+
+ d = 200.11;
+ assertEquals("Sign ", plus, MathX.sign(d));
+
+ d = 2000000000000.11;
+ assertEquals("Sign ", plus, MathX.sign(d));
+
+ }
+
+ public void testSinh() {
+ double d = 0;
+ d = MathX.sinh(0);
+ assertEquals("sinh 0", 0, d);
+
+ d = MathX.sinh(1);
+ assertEquals("sinh 1 ", 1.175201194, d);
+
+ d = MathX.sinh(-1);
+ assertEquals("sinh -1 ", -1.175201194, d);
+
+ d = MathX.sinh(-100);
+ assertEquals("sinh -100 ", -1.344058570908070E+43, d);
+
+ d = MathX.sinh(100);
+ assertEquals("sinh 100 ", 1.344058570908070E+43, d);
+
+ d = MathX.sinh(15);
+ assertEquals("sinh 15", 1634508.686, d);
+
+ d = MathX.sinh(-15);
+ assertEquals("sinh -15 ", -1634508.686, d);
+
+ d = MathX.sinh(0.1);
+ assertEquals("sinh 0.1", 0.10016675, d);
+
+ d = MathX.sinh(-0.1);
+ assertEquals("sinh -0.1 ", -0.10016675, d);
+
+ }
+
+ public void testSum() {
+ double[] d = new double[100];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ double s = MathX.sum(d);
+ assertEquals("Sum ", 212, s);
+
+ d = new double[1000];
+ s = MathX.sum(d);
+ assertEquals("Sum ", 0, s);
+
+ d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1;
+ d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1;
+ d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1;
+ d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1;
+ d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1;
+ s = MathX.sum(d);
+ assertEquals("Sum ", 10, s);
+
+ d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1;
+ d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1;
+ d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1;
+ d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1;
+ d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1;
+ s = MathX.sum(d);
+ assertEquals("Sum ", -212, s);
+
+ }
+
+ public void testSumproduct() {
+ double d = 0;
+ double[][] darr = new double[][]
+ {{0 ,0.11 ,23.23},
+ {1 ,0.22 ,46.46},
+ {2 ,0.33 ,69.69},
+ {3 ,0.44 ,92.92},
+ {4 ,0.55 ,116.15},
+ {5 ,0.66 ,139.38},
+ {6 ,0.77 ,162.61},
+ {7 ,0.88 ,185.84},
+ {8 ,0.99 ,209.07},
+ {9 ,1.1 ,232.3},
+ {10 ,1.21 ,255.53}};
+ d = MathX.sumproduct(darr);
+ assertEquals("Sumproduct ", 4.243234425E+22, d);
+ darr = new double[][]
+ {{0 ,0.11 ,23.23},
+ {0 ,0.22 ,46.46},
+ {0 ,0.33 ,69.69},
+ {0 ,0.44 ,92.92},
+ {0 ,0.55 ,116.15},
+ {0 ,0.66 ,139.38},
+ {0 ,0.77 ,162.61},
+ {0 ,0.88 ,185.84},
+ {0 ,0.99 ,209.07},
+ {0 ,1.1 ,232.3},
+ {0 ,1.21 ,255.53}};
+ d = MathX.sumproduct(darr);
+ assertEquals("Sumproduct ", 4.243234425E+22, d);
+
+ darr = new double[][]
+ {{0, 0, 0, 0, 0, 0, 0, 0},
+ {0.11, 0.22, 0.33, 0.44, 0.55, 0.66, 0.77, 0.88},
+ {23.23, 46.46, 69.69, 92.92, 116.15, 139.38, 162.61, 185.84}};
+ d = MathX.sumproduct(darr);
+ assertEquals("Sumproduct ", 0, d);
+
+ darr = new double[][]
+ {{0, 1, 2, 3, 4, 5, 6, 7},
+ {0.11, 0.22, 0.33, 0.44, 0.55, 0.66, 0.77, 0.88},
+ {23.23, 46.46, 69.69, 92.92, 116.15, 139.38, 162.61, 185.84}};
+ d = MathX.sumproduct(darr);
+ assertEquals("Sumproduct ", 2790.3876, d);
+
+
+ }
+
+ public void testSumsq() {
+ double[] d = new double[100];
+ d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1;
+ d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1;
+ d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1;
+ d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1;
+ d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1;
+
+ double s = MathX.sumsq(d);
+ assertEquals("Sumsq ", 2912.2, s);
+
+ d = new double[1000];
+ s = MathX.sumsq(d);
+ assertEquals("Sumsq ", 0, s);
+
+ d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1;
+ d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1;
+ d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1;
+ d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1;
+ d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1;
+ s = MathX.sumsq(d);
+ assertEquals("Sumsq ", 2912.2, s);
+
+ d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1;
+ d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1;
+ d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1;
+ d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1;
+ d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1;
+ s = MathX.sumsq(d);
+ assertEquals("Sumsq ", 2912.2, s);
+ }
+
+ public void testFactorial() {
+ int n = 0;
+ double s = 0;
+
+ n = 0;
+ s = MathX.factorial(n);
+ assertEquals("Factorial ", 1, s);
+
+ n = 1;
+ s = MathX.factorial(n);
+ assertEquals("Factorial ", 1, s);
+
+ n = 10;
+ s = MathX.factorial(n);
+ assertEquals("Factorial ", 3628800, s);
+
+ n = 99;
+ s = MathX.factorial(n);
+ assertEquals("Factorial ", 9.33262154439E+155, s);
+
+ n = -1;
+ s = MathX.factorial(n);
+ assertEquals("Factorial ", Double.NaN, s);
+
+ n = Integer.MAX_VALUE;
+ s = MathX.factorial(n);
+ assertEquals("Factorial ", Double.POSITIVE_INFINITY, s);
+ }
+
+ public void testSumx2my2() {
+ double d = 0;
+ double[] xarr = null;
+ double[] yarr = null;
+
+ xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ d = MathX.sumx2my2(xarr, yarr);
+ assertEquals("sumx2my2 ", 100, d);
+
+ xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
+ yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ d = MathX.sumx2my2(xarr, yarr);
+ assertEquals("sumx2my2 ", 100, d);
+
+ xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ d = MathX.sumx2my2(xarr, yarr);
+ assertEquals("sumx2my2 ", -100, d);
+
+ xarr = new double[]{10};
+ yarr = new double[]{9};
+ d = MathX.sumx2my2(xarr, yarr);
+ assertEquals("sumx2my2 ", 19, d);
+
+ xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ d = MathX.sumx2my2(xarr, yarr);
+ assertEquals("sumx2my2 ", 0, d);
+
+ }
+
+ public void testSumx2py2() {
+ double d = 0;
+ double[] xarr = null;
+ double[] yarr = null;
+
+ xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ d = MathX.sumx2py2(xarr, yarr);
+ assertEquals("sumx2py2 ", 670, d);
+
+ xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
+ yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ d = MathX.sumx2py2(xarr, yarr);
+ assertEquals("sumx2py2 ", 670, d);
+
+ xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ d = MathX.sumx2py2(xarr, yarr);
+ assertEquals("sumx2py2 ", 670, d);
+
+ xarr = new double[]{10};
+ yarr = new double[]{9};
+ d = MathX.sumx2py2(xarr, yarr);
+ assertEquals("sumx2py2 ", 181, d);
+
+ xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ d = MathX.sumx2py2(xarr, yarr);
+ assertEquals("sumx2py2 ", 770, d);
+ }
+
+ public void testSumxmy2() {
+ double d = 0;
+ double[] xarr = null;
+ double[] yarr = null;
+
+ xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ d = MathX.sumxmy2(xarr, yarr);
+ assertEquals("sumxmy2 ", 10, d);
+
+ xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
+ yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ d = MathX.sumxmy2(xarr, yarr);
+ assertEquals("sumxmy2 ", 1330, d);
+
+ xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ d = MathX.sumxmy2(xarr, yarr);
+ assertEquals("sumxmy2 ", 10, d);
+
+ xarr = new double[]{10};
+ yarr = new double[]{9};
+ d = MathX.sumxmy2(xarr, yarr);
+ assertEquals("sumxmy2 ", 1, d);
+
+ xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ d = MathX.sumxmy2(xarr, yarr);
+ assertEquals("sumxmy2 ", 0, d);
+ }
+
+ public void testRound() {
+ double d = 0;
+ int p = 0;
+
+ d = 0; p = 0;
+ assertEquals("round ", 0, MathX.round(d, p));
+
+ d = 10; p = 0;
+ assertEquals("round ", 10, MathX.round(d, p));
+
+ d = 123.23; p = 0;
+ assertEquals("round ", 123, MathX.round(d, p));
+
+ d = -123.23; p = 0;
+ assertEquals("round ", -123, MathX.round(d, p));
+
+ d = 123.12; p = 2;
+ assertEquals("round ", 123.12, MathX.round(d, p));
+
+ d = 88.123459; p = 5;
+ assertEquals("round ", 88.12346, MathX.round(d, p));
+
+ d = 0; p = 2;
+ assertEquals("round ", 0, MathX.round(d, p));
+
+ d = 0; p = -1;
+ assertEquals("round ", 0, MathX.round(d, p));
+
+ d = 0.01; p = -1;
+ assertEquals("round ", 0, MathX.round(d, p));
+
+ d = 123.12; p = -2;
+ assertEquals("round ", 100, MathX.round(d, p));
+
+ d = 88.123459; p = -3;
+ assertEquals("round ", 0, MathX.round(d, p));
+
+ d = 49.00000001; p = -1;
+ assertEquals("round ", 50, MathX.round(d, p));
+
+ d = 149.999999; p = -2;
+ assertEquals("round ", 100, MathX.round(d, p));
+
+ d = 150.0; p = -2;
+ assertEquals("round ", 200, MathX.round(d, p));
+ }
+
+ public void testRoundDown() {
+ double d = 0;
+ int p = 0;
+
+ d = 0; p = 0;
+ assertEquals("roundDown ", 0, MathX.roundDown(d, p));
+
+ d = 10; p = 0;
+ assertEquals("roundDown ", 10, MathX.roundDown(d, p));
+
+ d = 123.99; p = 0;
+ assertEquals("roundDown ", 123, MathX.roundDown(d, p));
+
+ d = -123.99; p = 0;
+ assertEquals("roundDown ", -123, MathX.roundDown(d, p));
+
+ d = 123.99; p = 2;
+ assertEquals("roundDown ", 123.99, MathX.roundDown(d, p));
+
+ d = 88.123459; p = 5;
+ assertEquals("roundDown ", 88.12345, MathX.roundDown(d, p));
+
+ d = 0; p = 2;
+ assertEquals("roundDown ", 0, MathX.roundDown(d, p));
+
+ d = 0; p = -1;
+ assertEquals("roundDown ", 0, MathX.roundDown(d, p));
+
+ d = 0.01; p = -1;
+ assertEquals("roundDown ", 0, MathX.roundDown(d, p));
+
+ d = 199.12; p = -2;
+ assertEquals("roundDown ", 100, MathX.roundDown(d, p));
+
+ d = 88.123459; p = -3;
+ assertEquals("roundDown ", 0, MathX.roundDown(d, p));
+
+ d = 99.00000001; p = -1;
+ assertEquals("roundDown ", 90, MathX.roundDown(d, p));
+
+ d = 100.00001; p = -2;
+ assertEquals("roundDown ", 100, MathX.roundDown(d, p));
+
+ d = 150.0; p = -2;
+ assertEquals("roundDown ", 100, MathX.roundDown(d, p));
+ }
+
+ public void testRoundUp() {
+ double d = 0;
+ int p = 0;
+
+ d = 0; p = 0;
+ assertEquals("roundUp ", 0, MathX.roundUp(d, p));
+
+ d = 10; p = 0;
+ assertEquals("roundUp ", 10, MathX.roundUp(d, p));
+
+ d = 123.23; p = 0;
+ assertEquals("roundUp ", 124, MathX.roundUp(d, p));
+
+ d = -123.23; p = 0;
+ assertEquals("roundUp ", -124, MathX.roundUp(d, p));
+
+ d = 123.12; p = 2;
+ assertEquals("roundUp ", 123.12, MathX.roundUp(d, p));
+
+ d = 88.123459; p = 5;
+ assertEquals("roundUp ", 88.12346, MathX.roundUp(d, p));
+
+ d = 0; p = 2;
+ assertEquals("roundUp ", 0, MathX.roundUp(d, p));
+
+ d = 0; p = -1;
+ assertEquals("roundUp ", 0, MathX.roundUp(d, p));
+
+ d = 0.01; p = -1;
+ assertEquals("roundUp ", 10, MathX.roundUp(d, p));
+
+ d = 123.12; p = -2;
+ assertEquals("roundUp ", 200, MathX.roundUp(d, p));
+
+ d = 88.123459; p = -3;
+ assertEquals("roundUp ", 1000, MathX.roundUp(d, p));
+
+ d = 49.00000001; p = -1;
+ assertEquals("roundUp ", 50, MathX.roundUp(d, p));
+
+ d = 149.999999; p = -2;
+ assertEquals("roundUp ", 200, MathX.roundUp(d, p));
+
+ d = 150.0; p = -2;
+ assertEquals("roundUp ", 200, MathX.roundUp(d, p));
+ }
+
+ public void testCeiling() {
+ double d = 0;
+ double s = 0;
+
+ d = 0; s = 0;
+ assertEquals("ceiling ", 0, MathX.ceiling(d, s));
+
+ d = 1; s = 0;
+ assertEquals("ceiling ", 0, MathX.ceiling(d, s));
+
+ d = 0; s = 1;
+ assertEquals("ceiling ", 0, MathX.ceiling(d, s));
+
+ d = -1; s = 0;
+ assertEquals("ceiling ", 0, MathX.ceiling(d, s));
+
+ d = 0; s = -1;
+ assertEquals("ceiling ", 0, MathX.ceiling(d, s));
+
+ d = 10; s = 1.11;
+ assertEquals("ceiling ", 11.1, MathX.ceiling(d, s));
+
+ d = 11.12333; s = 0.03499;
+ assertEquals("ceiling ", 11.12682, MathX.ceiling(d, s));
+
+ d = -11.12333; s = 0.03499;
+ assertEquals("ceiling ", Double.NaN, MathX.ceiling(d, s));
+
+ d = 11.12333; s = -0.03499;
+ assertEquals("ceiling ", Double.NaN, MathX.ceiling(d, s));
+
+ d = -11.12333; s = -0.03499;
+ assertEquals("ceiling ", -11.12682, MathX.ceiling(d, s));
+
+ d = 100; s = 0.001;
+ assertEquals("ceiling ", 100, MathX.ceiling(d, s));
+
+ d = -0.001; s = -9.99;
+ assertEquals("ceiling ", -9.99, MathX.ceiling(d, s));
+
+ d = 4.42; s = 0.05;
+ assertEquals("ceiling ", 4.45, MathX.ceiling(d, s));
+
+ d = 0.05; s = 4.42;
+ assertEquals("ceiling ", 4.42, MathX.ceiling(d, s));
+
+ d = 0.6666; s = 3.33;
+ assertEquals("ceiling ", 3.33, MathX.ceiling(d, s));
+
+ d = 2d/3; s = 3.33;
+ assertEquals("ceiling ", 3.33, MathX.ceiling(d, s));
+ }
+
+ public void testFloor() {
+ double d = 0;
+ double s = 0;
+
+ d = 0; s = 0;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+
+ d = 1; s = 0;
+ assertEquals("floor ", Double.NaN, MathX.floor(d, s));
+
+ d = 0; s = 1;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+
+ d = -1; s = 0;
+ assertEquals("floor ", Double.NaN, MathX.floor(d, s));
+
+ d = 0; s = -1;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+
+ d = 10; s = 1.11;
+ assertEquals("floor ", 9.99, MathX.floor(d, s));
+
+ d = 11.12333; s = 0.03499;
+ assertEquals("floor ", 11.09183, MathX.floor(d, s));
+
+ d = -11.12333; s = 0.03499;
+ assertEquals("floor ", Double.NaN, MathX.floor(d, s));
+
+ d = 11.12333; s = -0.03499;
+ assertEquals("floor ", Double.NaN, MathX.floor(d, s));
+
+ d = -11.12333; s = -0.03499;
+ assertEquals("floor ", -11.09183, MathX.floor(d, s));
+
+ d = 100; s = 0.001;
+ assertEquals("floor ", 100, MathX.floor(d, s));
+
+ d = -0.001; s = -9.99;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+
+ d = 4.42; s = 0.05;
+ assertEquals("floor ", 4.4, MathX.floor(d, s));
+
+ d = 0.05; s = 4.42;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+
+ d = 0.6666; s = 3.33;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+
+ d = 2d/3; s = 3.33;
+ assertEquals("floor ", 0, MathX.floor(d, s));
+ }
+
+}
--- /dev/null
+/*
+ * Created on May 30, 2005
+ *
+ */
+package org.apache.poi.hssf.record.formula.functions;
+
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public class TestStatsLib extends AbstractNumericTestCase {
+
+ public void testDevsq() {
+ double[] v = null;
+ double d, x = 0;
+
+ v = new double[] {1,2,3,4,5,6,7,8,9,10};
+ d = StatsLib.devsq(v);
+ x = 82.5;
+ assertEquals("devsq ", x, d);
+
+ v = new double[] {1,1,1,1,1,1,1,1,1,1};
+ d = StatsLib.devsq(v);
+ x = 0;
+ assertEquals("devsq ", x, d);
+
+ v = new double[] {0,0,0,0,0,0,0,0,0,0};
+ d = StatsLib.devsq(v);
+ x = 0;
+ assertEquals("devsq ", x, d);
+
+ v = new double[] {1,2,1,2,1,2,1,2,1,2};
+ d = StatsLib.devsq(v);
+ x = 2.5;
+ assertEquals("devsq ", x, d);
+
+ v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
+ d = StatsLib.devsq(v);
+ x = 10953.7416965767;
+ assertEquals("devsq ", x, d);
+
+ v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.devsq(v);
+ x = 82.5;
+ assertEquals("devsq ", x, d);
+ }
+
+ public void testKthLargest() {
+ double[] v = null;
+ double d, x = 0;
+
+ v = new double[] {1,2,3,4,5,6,7,8,9,10};
+ d = StatsLib.kthLargest(v, 3);
+ x = 8;
+ assertEquals("kthLargest ", x, d);
+
+ v = new double[] {1,1,1,1,1,1,1,1,1,1};
+ d = StatsLib.kthLargest(v, 3);
+ x = 1;
+ assertEquals("kthLargest ", x, d);
+
+ v = new double[] {0,0,0,0,0,0,0,0,0,0};
+ d = StatsLib.kthLargest(v, 3);
+ x = 0;
+ assertEquals("kthLargest ", x, d);
+
+ v = new double[] {1,2,1,2,1,2,1,2,1,2};
+ d = StatsLib.kthLargest(v, 3);
+ x = 2;
+ assertEquals("kthLargest ", x, d);
+
+ v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
+ d = StatsLib.kthLargest(v, 3);
+ x = 5.37828;
+ assertEquals("kthLargest ", x, d);
+
+ v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.kthLargest(v, 3);
+ x = -3;
+ assertEquals("kthLargest ", x, d);
+ }
+
+ public void testKthSmallest() {
+ }
+
+ public void testAvedev() {
+ double[] v = null;
+ double d, x = 0;
+
+ v = new double[] {1,2,3,4,5,6,7,8,9,10};
+ d = StatsLib.avedev(v);
+ x = 2.5;
+ assertEquals("avedev ", x, d);
+
+ v = new double[] {1,1,1,1,1,1,1,1,1,1};
+ d = StatsLib.avedev(v);
+ x = 0;
+ assertEquals("avedev ", x, d);
+
+ v = new double[] {0,0,0,0,0,0,0,0,0,0};
+ d = StatsLib.avedev(v);
+ x = 0;
+ assertEquals("avedev ", x, d);
+
+ v = new double[] {1,2,1,2,1,2,1,2,1,2};
+ d = StatsLib.avedev(v);
+ x = 0.5;
+ assertEquals("avedev ", x, d);
+
+ v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
+ d = StatsLib.avedev(v);
+ x = 36.42176053333;
+ assertEquals("avedev ", x, d);
+
+ v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.avedev(v);
+ x = 2.5;
+ assertEquals("avedev ", x, d);
+ }
+
+ public void testMedian() {
+ double[] v = null;
+ double d, x = 0;
+
+ v = new double[] {1,2,3,4,5,6,7,8,9,10};
+ d = StatsLib.median(v);
+ x = 5.5;
+ assertEquals("median ", x, d);
+
+ v = new double[] {1,1,1,1,1,1,1,1,1,1};
+ d = StatsLib.median(v);
+ x = 1;
+ assertEquals("median ", x, d);
+
+ v = new double[] {0,0,0,0,0,0,0,0,0,0};
+ d = StatsLib.median(v);
+ x = 0;
+ assertEquals("median ", x, d);
+
+ v = new double[] {1,2,1,2,1,2,1,2,1,2};
+ d = StatsLib.median(v);
+ x = 1.5;
+ assertEquals("median ", x, d);
+
+ v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
+ d = StatsLib.median(v);
+ x = 5.37828;
+ assertEquals("median ", x, d);
+
+ v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.median(v);
+ x = -5.5;
+ assertEquals("median ", x, d);
+
+ v = new double[] {-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.median(v);
+ x = -6;
+ assertEquals("median ", x, d);
+
+ v = new double[] {1,2,3,4,5,6,7,8,9};
+ d = StatsLib.median(v);
+ x = 5;
+ assertEquals("median ", x, d);
+ }
+
+ public void testMode() {
+ double[] v = null;
+ double d, x = 0;
+
+ v = new double[] {1,2,3,4,5,6,7,8,9,10};
+ d = StatsLib.mode(v);
+ x = Double.NaN;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {1,1,1,1,1,1,1,1,1,1};
+ d = StatsLib.mode(v);
+ x = 1;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {0,0,0,0,0,0,0,0,0,0};
+ d = StatsLib.mode(v);
+ x = 0;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {1,2,1,2,1,2,1,2,1,2};
+ d = StatsLib.mode(v);
+ x = 1;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
+ d = StatsLib.mode(v);
+ x = Double.NaN;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.mode(v);
+ x = Double.NaN;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {1,2,3,4,1,1,1,1,0,0,0,0,0};
+ d = StatsLib.mode(v);
+ x = 1;
+ assertEquals("mode ", x, d);
+
+ v = new double[] {0,1,2,3,4,1,1,1,0,0,0,0,1};
+ d = StatsLib.mode(v);
+ x = 0;
+ assertEquals("mode ", x, d);
+ }
+
+ public void testStddev() {
+ double[] v = null;
+ double d, x = 0;
+
+ v = new double[] {1,2,3,4,5,6,7,8,9,10};
+ d = StatsLib.stdev(v);
+ x = 3.02765035410;
+ assertEquals("stdev ", x, d);
+
+ v = new double[] {1,1,1,1,1,1,1,1,1,1};
+ d = StatsLib.stdev(v);
+ x = 0;
+ assertEquals("stdev ", x, d);
+
+ v = new double[] {0,0,0,0,0,0,0,0,0,0};
+ d = StatsLib.stdev(v);
+ x = 0;
+ assertEquals("stdev ", x, d);
+
+ v = new double[] {1,2,1,2,1,2,1,2,1,2};
+ d = StatsLib.stdev(v);
+ x = 0.52704627669;
+ assertEquals("stdev ", x, d);
+
+ v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
+ d = StatsLib.stdev(v);
+ x = 52.33006233652;
+ assertEquals("stdev ", x, d);
+
+ v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
+ d = StatsLib.stdev(v);
+ x = 3.02765035410;
+ assertEquals("stdev ", x, d);
+ }
+}