retval[5] = AggregateFunction.AVERAGE;
retval[6] = AggregateFunction.MIN;
retval[7] = AggregateFunction.MAX;
- retval[8] = new RowFunc(); // ROW
- retval[9] = new Column();
- retval[10] = new Na();
+ retval[8] = RowFunc::evaluate; // ROW
+ retval[9] = Column::evaluate;
+ retval[10] = Na::evaluate;
retval[11] = new Npv();
retval[12] = AggregateFunction.STDEV;
retval[13] = NumericFunction.DOLLAR;
retval[71] = CalendarFieldFunction.HOUR;
retval[72] = CalendarFieldFunction.MINUTE;
retval[73] = CalendarFieldFunction.SECOND;
- retval[74] = new Now();
+ retval[74] = Now::evaluate;
retval[75] = new Areas();
retval[76] = new Rows();
retval[77] = new Columns();
retval[216] = new Rank();
retval[219] = new Address();
retval[220] = new Days360();
- retval[221] = new Today();
+ retval[221] = Today::evaluate;
//222: VBD
retval[227] = AggregateFunction.MEDIAN;
retval[276] = NumericFunction.COMBIN;
// 277: CONFIDENCE
// 278:CRITBINOM
- retval[279] = new Even();
+ retval[279] = NumericFunction.EVEN;
// 280: EXPONDIST
// 281: FDIST
// 282: FINV
// 295: NORMINV
// 296: NORMSINV
// 297: STANDARDIZE
- retval[298] = new Odd();
+ retval[298] = NumericFunction.ODD;
// 299: PERMUT
retval[300] = NumericFunction.POISSON;
// 301: TDIST
*/
public interface ArrayFunction {
-
+
/**
* @param args the evaluated function arguments. Empty values are represented with
- * {@link BlankEval} or {@link MissingArgEval}, never <code>null</code>.
+ * {@link BlankEval} or {@link MissingArgEval}, never {@code null}.
* @param srcRowIndex row index of the cell containing the formula under evaluation
* @param srcColumnIndex column index of the cell containing the formula under evaluation
- * @return The evaluated result, possibly an {@link ErrorEval}, never <code>null</code>.
+ * @return The evaluated result, possibly an {@link ErrorEval}, never {@code null}.
* <b>Note</b> - Excel uses the error code <i>#NUM!</i> instead of IEEE <i>NaN</i>, so when
* numeric functions evaluate to {@link Double#NaN} be sure to translate the result to {@link
* ErrorEval#NUM_ERROR}.
* Evaluate an array function with two arguments.
*
* @param arg0 the first function argument. Empty values are represented with
- * {@link BlankEval} or {@link MissingArgEval}, never <code>null</code>
+ * {@link BlankEval} or {@link MissingArgEval}, never {@code null}
* @param arg1 the first function argument. Empty values are represented with
- * @link BlankEval} or {@link MissingArgEval}, never <code>null</code>
+ * @link BlankEval} or {@link MissingArgEval}, never {@code null}
*
* @param srcRowIndex row index of the cell containing the formula under evaluation
* @param srcColumnIndex column index of the cell containing the formula under evaluation
- * @return The evaluated result, possibly an {@link ErrorEval}, never <code>null</code>.
+ * @return The evaluated result, possibly an {@link ErrorEval}, never {@code null}.
* <b>Note</b> - Excel uses the error code <i>#NUM!</i> instead of IEEE <i>NaN</i>, so when
* numeric functions evaluate to {@link Double#NaN} be sure to translate the result to {@link
* ErrorEval#NUM_ERROR}.
*/
default ValueEval evaluateTwoArrayArgs(ValueEval arg0, ValueEval arg1, int srcRowIndex, int srcColumnIndex,
BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) {
+ return _evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex, evalFunc);
+ }
+
+ default ValueEval evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
+ java.util.function.Function<ValueEval, ValueEval> evalFunc) {
+ return _evaluateOneArrayArg(arg0, srcRowIndex, srcColumnIndex, evalFunc);
+ }
+
+ static ValueEval _evaluateTwoArrayArgs(ValueEval arg0, ValueEval arg1, int srcRowIndex, int srcColumnIndex,
+ BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) {
int w1, w2, h1, h2;
int a1FirstCol = 0, a1FirstRow = 0;
if (arg0 instanceof AreaEval) {
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
}
- default ValueEval evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
- java.util.function.Function<ValueEval, ValueEval> evalFunc){
+
+ static ValueEval _evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
+ java.util.function.Function<ValueEval, ValueEval> evalFunc){
int w1, w2, h1, h2;
int a1FirstCol = 0, a1FirstRow = 0;
if (arg0 instanceof AreaEval) {
}
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
-
}
}
* <li> Numbers: 0 is false. Any other number is TRUE </li>
* <li> Areas: *all* cells in area are evaluated according to the above rules</li>
* </ol>
- *
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*/
public abstract class BooleanFunction implements Function,ArrayFunction {
return cumulativeResult || currentValue;
}
};
- public static final Function FALSE = new Fixed0ArgFunction() {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
- return BoolEval.FALSE;
- }
- };
- public static final Function TRUE = new Fixed0ArgFunction() {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
- return BoolEval.TRUE;
- }
- };
- abstract static class Boolean1ArgFunction extends Fixed1ArgFunction implements ArrayFunction {
- @Override
- public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
- if (args.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
- return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex,
- vA -> evaluate(srcRowIndex, srcColumnIndex, vA));
- }
+ public static final Function FALSE = BooleanFunction::evaluateFalse;
- }
+ public static final Function TRUE = BooleanFunction::evaluateTrue;
- public static final Function NOT = new Boolean1ArgFunction() {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
- boolean boolArgVal;
- try {
- ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
- Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
- boolArgVal = b == null ? false : b;
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
-
- return BoolEval.valueOf(!boolArgVal);
- }
- };
+ public static final Function NOT = BooleanFunction::evaluateNot;
@Override
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex,
vA -> evaluate(new ValueEval[]{vA}, srcRowIndex, srcColumnIndex));
}
+
+ private static ValueEval evaluateFalse(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.FALSE;
+ }
+
+ private static ValueEval evaluateTrue(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.TRUE;
+ }
+
+ private static ValueEval evaluateNot(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ java.util.function.Function<ValueEval, ValueEval> notInner = (va) -> {
+ try {
+ ValueEval ve = OperandResolver.getSingleValue(va, srcRowIndex, srcColumnIndex);
+ Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+ boolean boolArgVal = b != null && b;
+ return BoolEval.valueOf(!boolArgVal);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ };
+
+ return ArrayFunction._evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, notInner);
+ }
}
\ No newline at end of file
import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval;
-public final class Column implements Function0Arg, Function1Arg {
+public final class Column {
+ public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length > 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
- return new NumberEval(srcColumnIndex+1.);
- }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int rnum;
-
- if (arg0 instanceof AreaEval) {
- rnum = ((AreaEval) arg0).getFirstColumn();
- } else if (arg0 instanceof RefEval) {
- rnum = ((RefEval) arg0).getColumn();
+ if (args.length == 0) {
+ rnum = srcColumnIndex;
+ } else if (args[0] instanceof AreaEval) {
+ rnum = ((AreaEval) args[0]).getFirstColumn();
+ } else if (args[0] instanceof RefEval) {
+ rnum = ((RefEval) args[0]).getColumn();
} else {
// anything else is not valid argument
return ErrorEval.VALUE_INVALID;
return new NumberEval(rnum + 1.);
}
- public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
- switch (args.length) {
- case 1:
- return evaluate(srcRowIndex, srcColumnIndex, args[0]);
- case 0:
- return new NumberEval(srcColumnIndex+1.);
- }
- return ErrorEval.VALUE_INVALID;
- }
}
+++ /dev/null
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.functions;
-
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class Even extends NumericFunction.OneArg {
-
- private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
-
- protected double evaluate(double d) {
- if (d==0) {
- return 0;
- }
- long result;
- if (d>0) {
- result = calcEven(d);
- } else {
- result = -calcEven(-d);
- }
- return result;
- }
-
- private static long calcEven(double d) {
- long x = ((long) d) & PARITY_MASK;
- if (x == d) {
- return x;
- }
- return x + 2;
- }
-}
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.util.Removal;
/**
* Convenience base class for functions that only take zero arguments.
*
- * @author Josh Micich
+ * @deprecated replaced by lambda expressions in 5.0.1
*/
+@Deprecated
+@Removal(version = "6.0.0")
public abstract class Fixed0ArgFunction implements Function0Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 0) {
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula.functions;
+
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
+public class Log {
+ private static final double TEN = 10.0;
+ private static final double LOG_10_TO_BASE_e = Math.log(TEN);
+
+ public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 1 && args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ try {
+ double d0 = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+ double result;
+ if (args.length == 1) {
+ result = Math.log(d0) / LOG_10_TO_BASE_e;
+ } else {
+ double d1 = NumericFunction.singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
+ double logE = Math.log(d0);
+ result = (Double.compare(d1, Math.E) == 0) ? logE : (logE / Math.log(d1));
+ }
+ NumericFunction.checkValue(result);
+ return new NumberEval(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ }
+}
return round(n, p, java.math.RoundingMode.HALF_UP);
}
+ public static double round(double n, double p) {
+ return round(n, (int)p);
+ }
+
+
+
/**
* Returns a value rounded-up to p digits after decimal.
* If p is negative, then the number is rounded to
return round(n, p, java.math.RoundingMode.UP);
}
+ public static double roundUp(double n, double p) {
+ return roundUp(n, (int)p);
+ }
+
+
/**
* Returns a value rounded to p digits after decimal.
* If p is negative, then the number is rounded to
public static double roundDown(double n, int p) {
return round(n, p, java.math.RoundingMode.DOWN);
}
-
+
+ public static double roundDown(double n, double p) {
+ return roundDown(n, (int)p);
+ }
+
private static double round(double n, int p, java.math.RoundingMode rounding) {
if (Double.isNaN(n) || Double.isInfinite(n)) {
return Double.NaN;
return d;
}
+ public static double factorial(double d) {
+ return factorial((int)d);
+ }
+
/**
* returns the remainder resulting from operation:
/**
* Implementation of Excel function NA()
- *
- * @author Josh Micich
*/
-public final class Na extends Fixed0ArgFunction {
-
- public ValueEval evaluate(int srcCellRow, int srcCellCol) {
- return ErrorEval.NA;
+public final class Na {
+ public static ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
+ return args.length != 0 ? ErrorEval.VALUE_INVALID : ErrorEval.NA;
}
}
import java.util.Date;
+import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.DateUtil;
/**
* Implementation of Excel NOW() Function
- *
- * @author Frank Taffelt
*/
-public final class Now extends Fixed0ArgFunction {
-
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+public final class Now {
+ public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 0) {
+ return ErrorEval.VALUE_INVALID;
+ }
Date now = new Date(System.currentTimeMillis());
return new NumberEval(DateUtil.getExcelDate(now));
}
package org.apache.poi.ss.formula.functions;
+import static org.apache.poi.ss.formula.eval.ErrorEval.VALUE_INVALID;
+
import org.apache.poi.ss.formula.eval.*;
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- * @author Josh Micich
- * @author Stephen Wolke (smwolke at geistig.com)
- */
public abstract class NumericFunction implements Function {
- static final double ZERO = 0.0;
- static final double TEN = 10.0;
- static final double LOG_10_TO_BASE_e = Math.log(TEN);
+ private static final double ZERO = 0.0;
+ private static final double TEN = 10.0;
+ private static final double LOG_10_TO_BASE_e = Math.log(TEN);
+ private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
+
protected static double singleOperandEvaluate(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
if (arg == null) {
}
/**
- * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</tt> or <tt>Infinity</tt>
+ * @throws EvaluationException (#NUM!) if <tt>result</tt> is {@code NaN} or {@code Infinity}
*/
public static void checkValue(double result) throws EvaluationException {
if (Double.isNaN(result) || Double.isInfinite(result)) {
protected abstract double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException;
- /* -------------------------------------------------------------------------- */
- // intermediate sub-classes (one-arg, two-arg and multi-arg)
-
- public static abstract class OneArg extends Fixed1ArgFunction {
- protected OneArg() {
- // no fields to initialise
- }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
- double result;
- try {
- double d = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- result = evaluate(d);
- checkValue(result);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- return new NumberEval(result);
+ public static final Function ABS = oneDouble(Math::abs);
+ public static final Function ACOS = oneDouble(Math::acos);
+ public static final Function ACOSH = oneDouble(MathX::acosh);
+ public static final Function ASIN = oneDouble(Math::asin);
+ public static final Function ASINH = oneDouble(MathX::asinh);
+ public static final Function ATAN = oneDouble(Math::atan);
+ public static final Function ATANH = oneDouble(MathX::atanh);
+ public static final Function COS = oneDouble(Math::cos);
+ public static final Function COSH = oneDouble(MathX::cosh);
+ public static final Function DEGREES = oneDouble(Math::toDegrees);
+ public static final Function DOLLAR = NumericFunction::evaluateDollar;
+
+ private static ValueEval evaluateDollar(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 1 && args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
}
- protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
- if (args.length != 1) {
- throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ try {
+ double val = singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+ double d1 = args.length == 1 ? 2.0 : singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
+
+ // second arg converts to int by truncating toward zero
+ int nPlaces = (int)d1;
+
+ if (nPlaces > 127) {
+ return VALUE_INVALID;
}
- double d = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
- return evaluate(d);
+
+ // TODO - DOLLAR() function impl is NQR
+ // result should be StringEval, with leading '$' and thousands separators
+ // current junits are asserting incorrect behaviour
+ return new NumberEval(val);
+ }catch (EvaluationException e) {
+ return e.getErrorEval();
}
- protected abstract double evaluate(double d) throws EvaluationException;
}
- public static abstract class TwoArg extends Fixed2ArgFunction {
- protected TwoArg() {
- // no fields to initialise
- }
+ public static final Function EXP = oneDouble(d -> Math.pow(Math.E, d));
+ public static final Function FACT = oneDouble(MathX::factorial);
+ public static final Function INT = oneDouble(d -> Math.round(d-0.5));
+ public static final Function LN = oneDouble(Math::log);
+ public static final Function LOG10 = oneDouble(d -> Math.log(d) / LOG_10_TO_BASE_e);
+ public static final Function RADIANS = oneDouble(Math::toRadians);
+ public static final Function SIGN = oneDouble(MathX::sign);
+ public static final Function SIN = oneDouble(Math::sin);
+ public static final Function SINH = oneDouble(MathX::sinh);
+ public static final Function SQRT = oneDouble(Math::sqrt);
+ public static final Function TAN = oneDouble(Math::tan);
+ public static final Function TANH = oneDouble(MathX::tanh);
+ /* -------------------------------------------------------------------------- */
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
- double result;
- try {
- double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
- result = evaluate(d0, d1);
- checkValue(result);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
+ public static final Function ATAN2 = twoDouble((d0, d1) ->
+ (d0 == ZERO && d1 == ZERO) ? ErrorEval.DIV_ZERO : Math.atan2(d1, d0)
+ );
+
+ public static final Function CEILING = twoDouble(MathX::ceiling);
+
+ public static final Function COMBIN = twoDouble((d0, d1) ->
+ (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) ? ErrorEval.NUM_ERROR : MathX.nChooseK((int) d0, (int) d1));
+
+ public static final Function FLOOR = twoDouble((d0, d1) ->
+ (d1 == ZERO) ? (d0 == ZERO ? ZERO : ErrorEval.DIV_ZERO) : MathX.floor(d0, d1));
+
+ public static final Function MOD = twoDouble((d0, d1) ->
+ (d1 == ZERO) ? ErrorEval.DIV_ZERO : MathX.mod(d0, d1));
+
+ public static final Function POWER = twoDouble(Math::pow);
+
+ public static final Function ROUND = twoDouble(MathX::round);
+ public static final Function ROUNDDOWN = twoDouble(MathX::roundDown);
+ public static final Function ROUNDUP = twoDouble(MathX::roundUp);
+ public static final Function TRUNC = NumericFunction::evaluateTrunc;
+
+ private static ValueEval evaluateTrunc(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 1 && args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ try {
+ double d0 = singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+ double d1 = args.length == 1 ? 0 : singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
+ double result = MathX.roundDown(d0, d1);
+ checkValue(result);
return new NumberEval(result);
+ }catch (EvaluationException e) {
+ return e.getErrorEval();
}
-
- protected abstract double evaluate(double d0, double d1) throws EvaluationException;
}
/* -------------------------------------------------------------------------- */
- public static final Function ABS = new OneArg() {
- protected double evaluate(double d) {
- return Math.abs(d);
- }
- };
- public static final Function ACOS = new OneArg() {
- protected double evaluate(double d) {
- return Math.acos(d);
- }
- };
- public static final Function ACOSH = new OneArg() {
- protected double evaluate(double d) {
- return MathX.acosh(d);
- }
- };
- public static final Function ASIN = new OneArg() {
- protected double evaluate(double d) {
- return Math.asin(d);
- }
- };
- public static final Function ASINH = new OneArg() {
- protected double evaluate(double d) {
- return MathX.asinh(d);
- }
- };
- public static final Function ATAN = new OneArg() {
- protected double evaluate(double d) {
- return Math.atan(d);
- }
- };
- public static final Function ATANH = new OneArg() {
- protected double evaluate(double d) {
- return MathX.atanh(d);
- }
- };
- public static final Function COS = new OneArg() {
- protected double evaluate(double d) {
- return Math.cos(d);
- }
- };
- public static final Function COSH = new OneArg() {
- protected double evaluate(double d) {
- return MathX.cosh(d);
- }
- };
- public static final Function DEGREES = new OneArg() {
- protected double evaluate(double d) {
- return Math.toDegrees(d);
- }
- };
- static final NumberEval DOLLAR_ARG2_DEFAULT = new NumberEval(2.0);
- public static final Function DOLLAR = new Var1or2ArgFunction() {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
- return evaluate(srcRowIndex, srcColumnIndex, arg0, DOLLAR_ARG2_DEFAULT);
- }
+ public static final Function LOG = Log::evaluate;
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
- ValueEval arg1) {
- double val;
- double d1;
- try {
- val = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- // second arg converts to int by truncating toward zero
- int nPlaces = (int)d1;
+ static final NumberEval PI_EVAL = new NumberEval(Math.PI);
+ public static final Function PI = NumericFunction::evaluatePI;
- if (nPlaces > 127) {
- return ErrorEval.VALUE_INVALID;
- }
+ private static ValueEval evaluatePI(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ return (args.length != 0) ? ErrorEval.VALUE_INVALID : PI_EVAL;
+ }
+ public static final Function RAND = NumericFunction::evaluateRand;
- // TODO - DOLLAR() function impl is NQR
- // result should be StringEval, with leading '$' and thousands separators
- // current junits are asserting incorrect behaviour
- return new NumberEval(val);
- }
- };
- public static final Function EXP = new OneArg() {
- protected double evaluate(double d) {
- return Math.pow(Math.E, d);
- }
- };
- public static final Function FACT = new OneArg() {
- protected double evaluate(double d) {
- return MathX.factorial((int)d);
- }
- };
- public static final Function INT = new OneArg() {
- protected double evaluate(double d) {
- return Math.round(d-0.5);
- }
- };
- public static final Function LN = new OneArg() {
- protected double evaluate(double d) {
- return Math.log(d);
- }
- };
- public static final Function LOG10 = new OneArg() {
- protected double evaluate(double d) {
- return Math.log(d) / LOG_10_TO_BASE_e;
- }
- };
- public static final Function RADIANS = new OneArg() {
- protected double evaluate(double d) {
- return Math.toRadians(d);
- }
- };
- public static final Function SIGN = new OneArg() {
- protected double evaluate(double d) {
- return MathX.sign(d);
- }
- };
- public static final Function SIN = new OneArg() {
- protected double evaluate(double d) {
- return Math.sin(d);
- }
- };
- public static final Function SINH = new OneArg() {
- protected double evaluate(double d) {
- return MathX.sinh(d);
- }
- };
- public static final Function SQRT = new OneArg() {
- protected double evaluate(double d) {
- return Math.sqrt(d);
- }
- };
+ private static ValueEval evaluateRand(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ return (args.length != 0) ? ErrorEval.VALUE_INVALID : new NumberEval(Math.random());
+ }
- public static final Function TAN = new OneArg() {
- protected double evaluate(double d) {
- return Math.tan(d);
- }
- };
- public static final Function TANH = new OneArg() {
- protected double evaluate(double d) {
- return MathX.tanh(d);
- }
- };
+ public static final Function POISSON = Poisson::evaluate;
- /* -------------------------------------------------------------------------- */
+ public static final Function ODD = oneDouble(NumericFunction::evaluateOdd);
- public static final Function ATAN2 = new TwoArg() {
- protected double evaluate(double d0, double d1) throws EvaluationException {
- if (d0 == ZERO && d1 == ZERO) {
- throw new EvaluationException(ErrorEval.DIV_ZERO);
- }
- return Math.atan2(d1, d0);
- }
- };
- public static final Function CEILING = new TwoArg() {
- protected double evaluate(double d0, double d1) {
- return MathX.ceiling(d0, d1);
- }
- };
- public static final Function COMBIN = new TwoArg() {
- protected double evaluate(double d0, double d1) throws EvaluationException {
- if (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) {
- throw new EvaluationException(ErrorEval.NUM_ERROR);
- }
- return MathX.nChooseK((int) d0, (int) d1);
- }
- };
- public static final Function FLOOR = new TwoArg() {
- protected double evaluate(double d0, double d1) throws EvaluationException {
- if (d1 == ZERO) {
- if (d0 == ZERO) {
- return ZERO;
- }
- throw new EvaluationException(ErrorEval.DIV_ZERO);
- }
- return MathX.floor(d0, d1);
+ private static double evaluateOdd(double d) {
+ if (d==0) {
+ return 1;
}
- };
- public static final Function MOD = new TwoArg() {
- protected double evaluate(double d0, double d1) throws EvaluationException {
- if (d1 == ZERO) {
- throw new EvaluationException(ErrorEval.DIV_ZERO);
- }
- return MathX.mod(d0, d1);
- }
- };
- public static final Function POWER = new TwoArg() {
- protected double evaluate(double d0, double d1) {
- return Math.pow(d0, d1);
- }
- };
- public static final Function ROUND = new TwoArg() {
- protected double evaluate(double d0, double d1) {
- return MathX.round(d0, (int)d1);
- }
- };
- public static final Function ROUNDDOWN = new TwoArg() {
- protected double evaluate(double d0, double d1) {
- return MathX.roundDown(d0, (int)d1);
- }
- };
- public static final Function ROUNDUP = new TwoArg() {
- protected double evaluate(double d0, double d1) {
- return MathX.roundUp(d0, (int)d1);
- }
- };
- static final NumberEval TRUNC_ARG2_DEFAULT = new NumberEval(0);
- public static final Function TRUNC = new Var1or2ArgFunction() {
+ double dpm = Math.abs(d)+1;
+ long x = ((long) dpm) & PARITY_MASK;
+ return MathX.sign(d) * ((Double.compare(x, dpm) == 0) ? x-1 : x+1);
+ }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
- return evaluate(srcRowIndex, srcColumnIndex, arg0, TRUNC_ARG2_DEFAULT);
- }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
- double result;
- try {
- double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
- result = MathX.roundDown(d0, (int)d1);
- checkValue(result);
- }catch (EvaluationException e) {
- return e.getErrorEval();
- }
- return new NumberEval(result);
+ public static final Function EVEN = oneDouble(NumericFunction::evaluateEven);
+
+ private static double evaluateEven(double d) {
+ if (d==0) {
+ return 0;
}
- };
- /* -------------------------------------------------------------------------- */
+ double dpm = Math.abs(d);
+ long x = ((long) dpm) & PARITY_MASK;
+ return MathX.sign(d) * ((Double.compare(x, dpm) == 0) ? x : (x + 2));
+ }
- private static final class Log extends Var1or2ArgFunction {
- public Log() {
- // no instance fields
- }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
- double result;
- try {
- double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- result = Math.log(d0) / LOG_10_TO_BASE_e;
- NumericFunction.checkValue(result);
- } catch (EvaluationException e) {
- return e.getErrorEval();
+
+ private interface OneDoubleIf {
+ double apply(double d);
+ }
+
+ private static Function oneDouble(OneDoubleIf doubleFun) {
+ return (args, srcCellRow, srcCellCol) -> {
+ if (args.length != 1) {
+ return VALUE_INVALID;
}
- return new NumberEval(result);
- }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
- ValueEval arg1) {
- double result;
try {
- double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
- double logE = Math.log(d0);
- if (Double.compare(d1, Math.E) == 0) {
- result = logE;
- } else {
- result = logE / Math.log(d1);
- }
- NumericFunction.checkValue(result);
+ double d = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
+ double res = doubleFun.apply(d);
+ return (Double.isNaN(res) || Double.isInfinite(res)) ? ErrorEval.NUM_ERROR : new NumberEval(res);
} catch (EvaluationException e) {
return e.getErrorEval();
}
- return new NumberEval(result);
- }
+ };
}
- public static final Function LOG = new Log();
-
- static final NumberEval PI_EVAL = new NumberEval(Math.PI);
- public static final Function PI = new Fixed0ArgFunction() {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
- return PI_EVAL;
- }
- };
- public static final Function RAND = new Fixed0ArgFunction() {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
- return new NumberEval(Math.random());
- }
- };
- public static final Function POISSON = new Fixed3ArgFunction() {
-
- private static final double DEFAULT_RETURN_RESULT =1;
-
- /**
- * This checks is x = 0 and the mean = 0.
- * Excel currently returns the value 1 where as the
- * maths common implementation will error.
- * @param x The number.
- * @param mean The mean.
- * @return If a default value should be returned.
- */
- private boolean isDefaultResult(double x, double mean) {
-
- if ( x == 0 && mean == 0 ) {
- return true;
- }
- return false;
- }
-
- private boolean checkArgument(double aDouble) throws EvaluationException {
-
- NumericFunction.checkValue(aDouble);
-
- // make sure that the number is positive
- if (aDouble < 0) {
- throw new EvaluationException(ErrorEval.NUM_ERROR);
- }
-
- return true;
- }
-
- private double probability(int k, double lambda) {
- return Math.pow(lambda, k) * Math.exp(-lambda) / factorial(k);
- }
-
- private double cumulativeProbability(int x, double lambda) {
- double result = 0;
- for(int k = 0; k <= x; k++){
- result += probability(k, lambda);
- }
- return result;
- }
-
- /** All long-representable factorials */
- private final long[] FACTORIALS = new long[] {
- 1l, 1l, 2l,
- 6l, 24l, 120l,
- 720l, 5040l, 40320l,
- 362880l, 3628800l, 39916800l,
- 479001600l, 6227020800l, 87178291200l,
- 1307674368000l, 20922789888000l, 355687428096000l,
- 6402373705728000l, 121645100408832000l, 2432902008176640000l };
-
-
- public long factorial(final int n) {
- if (n < 0 || n > 20) {
- throw new IllegalArgumentException("Valid argument should be in the range [0..20]");
- }
- return FACTORIALS[n];
- }
-
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2) {
-
- // arguments/result for this function
- double mean=0;
- double x=0;
- boolean cumulative = ((BoolEval)arg2).getBooleanValue();
- double result=0;
-
- try {
- x = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
- mean = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-
- // check for default result : excel implementation for 0,0
- // is different to Math Common.
- if (isDefaultResult(x,mean)) {
- return new NumberEval(DEFAULT_RETURN_RESULT);
- }
- // check the arguments : as per excel function def
- checkArgument(x);
- checkArgument(mean);
-
- // truncate x : as per excel function def
- if ( cumulative ) {
- result = cumulativeProbability((int)x, mean);
- } else {
- result = probability((int)x, mean);
- }
-
- // check the result
- NumericFunction.checkValue(result);
+ private interface TwoDoubleIf {
+ Object apply(double d1, double d2);
+ }
+ private static Function twoDouble(TwoDoubleIf doubleFun) {
+ return (args, srcCellRow, srcCellCol) -> {
+ if (args.length != 2) {
+ return VALUE_INVALID;
+ }
+ try {
+ double d1 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
+ double d2 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
+ Object res = doubleFun.apply(d1, d2);
+ if (res instanceof ErrorEval) {
+ return (ErrorEval)res;
+ }
+ assert(res instanceof Double);
+ double d = (Double)res;
+ return (Double.isNaN(d) || Double.isInfinite(d)) ? ErrorEval.NUM_ERROR : new NumberEval(d);
} catch (EvaluationException e) {
return e.getErrorEval();
}
-
- return new NumberEval(result);
-
- }
- };
+ };
+ }
}
+++ /dev/null
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.functions;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class Odd extends NumericFunction.OneArg {
- private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
-
- protected double evaluate(double d) {
- if (d==0) {
- return 1;
- }
- return (d>0) ? calcOdd(d) : -calcOdd(-d);
- }
-
- private static long calcOdd(double d) {
- double dpm1 = d+1;
- long x = ((long) dpm1) & PARITY_MASK;
- return ( Double.compare(x, dpm1) == 0 ) ? x-1 : x+1;
- }
-}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula.functions;
+
+import org.apache.poi.ss.formula.eval.BoolEval;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
+public class Poisson {
+
+ private static final double DEFAULT_RETURN_RESULT =1;
+
+ /** All long-representable factorials */
+ private static final long[] FACTORIALS = {
+ 1L, 1L, 2L,
+ 6L, 24L, 120L,
+ 720L, 5040L, 40320L,
+ 362880L, 3628800L, 39916800L,
+ 479001600L, 6227020800L, 87178291200L,
+ 1307674368000L, 20922789888000L, 355687428096000L,
+ 6402373705728000L, 121645100408832000L, 2432902008176640000L };
+
+ /**
+ * This checks is x = 0 and the mean = 0.
+ * Excel currently returns the value 1 where as the
+ * maths common implementation will error.
+ * @param x The number.
+ * @param mean The mean.
+ * @return If a default value should be returned.
+ */
+ private static boolean isDefaultResult(double x, double mean) {
+ return x == 0 && mean == 0;
+ }
+
+ private static void checkArgument(double aDouble) throws EvaluationException {
+ NumericFunction.checkValue(aDouble);
+
+ // make sure that the number is positive
+ if (aDouble < 0) {
+ throw new EvaluationException(ErrorEval.NUM_ERROR);
+ }
+ }
+
+ private static double probability(int k, double lambda) {
+ return Math.pow(lambda, k) * Math.exp(-lambda) / factorial(k);
+ }
+
+ private static double cumulativeProbability(int x, double lambda) {
+ double result = 0;
+ for(int k = 0; k <= x; k++){
+ result += probability(k, lambda);
+ }
+ return result;
+ }
+
+ private static long factorial(final int n) {
+ if (n < 0 || n > 20) {
+ throw new IllegalArgumentException("Valid argument should be in the range [0..20]");
+ }
+ return FACTORIALS[n];
+ }
+
+ public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 3) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ ValueEval arg0 = args[0];
+ ValueEval arg1 = args[1];
+ ValueEval arg2 = args[2];
+
+ try {
+ // arguments/result for this function
+ double x = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+ double mean = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+
+ // check for default result : excel implementation for 0,0
+ // is different to Math Common.
+ if (isDefaultResult(x,mean)) {
+ return new NumberEval(DEFAULT_RETURN_RESULT);
+ }
+ // check the arguments : as per excel function def
+ checkArgument(x);
+ checkArgument(mean);
+
+ // truncate x : as per excel function def
+ boolean cumulative = ((BoolEval)arg2).getBooleanValue();
+ double result = cumulative ? cumulativeProbability((int) x, mean) : probability((int) x, mean);
+
+ // check the result
+ NumericFunction.checkValue(result);
+
+ return new NumberEval(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ }
+
+}
/**
* Implementation for the Excel function ROW
*/
-public final class RowFunc implements Function0Arg, Function1Arg {
+public final class RowFunc {
+ public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length > 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
- return new NumberEval(srcRowIndex+1.);
- }
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int rnum;
-
- if (arg0 instanceof AreaEval) {
- rnum = ((AreaEval) arg0).getFirstRow();
- } else if (arg0 instanceof RefEval) {
- rnum = ((RefEval) arg0).getRow();
+ if (args.length == 0) {
+ rnum = srcRowIndex;
+ } else if (args[0] instanceof AreaEval) {
+ rnum = ((AreaEval) args[0]).getFirstRow();
+ } else if (args[0] instanceof RefEval) {
+ rnum = ((RefEval) args[0]).getRow();
} else {
// anything else is not valid argument
return ErrorEval.VALUE_INVALID;
return new NumberEval(rnum + 1.);
}
- public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
- switch (args.length) {
- case 1:
- return evaluate(srcRowIndex, srcColumnIndex, args[0]);
- case 0:
- return new NumberEval(srcRowIndex+1.);
- }
- return ErrorEval.VALUE_INVALID;
- }
}
import java.util.Calendar;
+import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.DateUtil;
/**
* Implementation of Excel TODAY() Function<br>
*/
-public final class Today extends Fixed0ArgFunction {
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+public final class Today {
+ public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ if (args.length != 0) {
+ return ErrorEval.VALUE_INVALID;
+ }
Calendar now = LocaleUtil.getLocaleCalendar();
now.clear(Calendar.HOUR);
now.set(Calendar.HOUR_OF_DAY,0);
/**
* Tests for ROW(), ROWS(), COLUMN(), COLUMNS()
- *
- * @author Josh Micich
*/
final class TestRowCol {
@Test
void testCol() {
- Function target = new Column();
+ Function target = Column::evaluate;
{
ValueEval[] args = { EvalFactory.createRefEval("C5"), };
double actual = NumericFunctionInvoker.invoke(target, args);
@Test
void testRow() {
- Function target = new RowFunc();
+ Function target = RowFunc::evaluate;
{
ValueEval[] args = { EvalFactory.createRefEval("C5"), };
double actual = NumericFunctionInvoker.invoke(target, args);